feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
"""Tests for telemetry module (data flywheel)."""
|
|
|
|
|
|
|
|
|
|
import os
|
2026-01-10 15:33:44 -08:00
|
|
|
import tempfile
|
|
|
|
|
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from headroom.telemetry import (
|
2026-01-10 15:33:44 -08:00
|
|
|
AnonymizedToolStats,
|
|
|
|
|
FieldDistribution,
|
|
|
|
|
RetrievalStats,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
TelemetryCollector,
|
|
|
|
|
TelemetryConfig,
|
2026-01-10 15:33:44 -08:00
|
|
|
ToolSignature,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
get_telemetry_collector,
|
|
|
|
|
reset_telemetry_collector,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
|
def reset_globals():
|
|
|
|
|
"""Reset global state before each test."""
|
|
|
|
|
reset_telemetry_collector()
|
|
|
|
|
yield
|
|
|
|
|
reset_telemetry_collector()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestFieldDistribution:
|
|
|
|
|
"""Test FieldDistribution data model."""
|
|
|
|
|
|
|
|
|
|
def test_to_dict(self):
|
|
|
|
|
"""to_dict serializes all fields."""
|
|
|
|
|
dist = FieldDistribution(
|
|
|
|
|
field_name_hash="abc12345",
|
|
|
|
|
field_type="string",
|
|
|
|
|
avg_length=50.5,
|
|
|
|
|
unique_ratio=0.8,
|
|
|
|
|
looks_like_id=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
d = dist.to_dict()
|
|
|
|
|
|
|
|
|
|
assert d["field_name_hash"] == "abc12345"
|
|
|
|
|
assert d["field_type"] == "string"
|
|
|
|
|
assert d["avg_length"] == 50.5
|
|
|
|
|
assert d["unique_ratio"] == 0.8
|
|
|
|
|
assert d["looks_like_id"] is True
|
|
|
|
|
|
|
|
|
|
def test_from_dict(self):
|
|
|
|
|
"""from_dict deserializes correctly."""
|
|
|
|
|
data = {
|
|
|
|
|
"field_name_hash": "xyz789",
|
|
|
|
|
"field_type": "numeric",
|
|
|
|
|
"has_variance": True,
|
|
|
|
|
"variance_bucket": "high",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dist = FieldDistribution.from_dict(data)
|
|
|
|
|
|
|
|
|
|
assert dist.field_name_hash == "xyz789"
|
|
|
|
|
assert dist.field_type == "numeric"
|
|
|
|
|
assert dist.has_variance is True
|
|
|
|
|
assert dist.variance_bucket == "high"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestToolSignature:
|
|
|
|
|
"""Test ToolSignature data model."""
|
|
|
|
|
|
|
|
|
|
def test_from_items_empty_list(self):
|
|
|
|
|
"""Empty list produces valid signature with unique hash.
|
|
|
|
|
|
|
|
|
|
HIGH FIX #5: Empty lists now get a proper hash instead of 'empty'
|
|
|
|
|
to prevent hash collisions between different empty-list scenarios.
|
|
|
|
|
"""
|
|
|
|
|
sig = ToolSignature.from_items([])
|
|
|
|
|
|
|
|
|
|
# Should get a proper hash, not 'empty' (which could cause collisions)
|
|
|
|
|
assert sig.structure_hash != "empty"
|
|
|
|
|
assert len(sig.structure_hash) == 24 # Our hash length
|
|
|
|
|
assert sig.field_count == 0
|
|
|
|
|
|
|
|
|
|
def test_from_items_single_item(self):
|
|
|
|
|
"""Single item produces valid signature."""
|
|
|
|
|
items = [{"id": "123", "name": "test", "score": 0.95}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.field_count == 3
|
|
|
|
|
assert sig.string_field_count == 2 # id, name
|
|
|
|
|
assert sig.numeric_field_count == 1 # score
|
|
|
|
|
assert sig.has_id_like_field is True
|
|
|
|
|
assert sig.has_score_like_field is True
|
|
|
|
|
|
|
|
|
|
def test_from_items_with_nested_objects(self):
|
|
|
|
|
"""Nested objects are detected."""
|
|
|
|
|
items = [{"data": {"nested": "value"}}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.has_nested_objects is True
|
|
|
|
|
assert sig.object_field_count == 1
|
|
|
|
|
|
|
|
|
|
def test_from_items_with_arrays(self):
|
|
|
|
|
"""Arrays are detected."""
|
|
|
|
|
items = [{"tags": ["a", "b", "c"]}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.has_arrays is True
|
|
|
|
|
assert sig.array_field_count == 1
|
|
|
|
|
|
|
|
|
|
def test_structure_hash_consistency(self):
|
|
|
|
|
"""Same structure produces same hash."""
|
|
|
|
|
items1 = [{"id": "123", "name": "alice"}]
|
|
|
|
|
items2 = [{"id": "456", "name": "bob"}]
|
|
|
|
|
|
|
|
|
|
sig1 = ToolSignature.from_items(items1)
|
|
|
|
|
sig2 = ToolSignature.from_items(items2)
|
|
|
|
|
|
|
|
|
|
assert sig1.structure_hash == sig2.structure_hash
|
|
|
|
|
|
|
|
|
|
def test_structure_hash_differs_for_different_structure(self):
|
|
|
|
|
"""Different structure produces different hash."""
|
|
|
|
|
items1 = [{"id": "123", "name": "alice"}]
|
|
|
|
|
items2 = [{"id": "123", "score": 0.5}] # Different fields
|
|
|
|
|
|
|
|
|
|
sig1 = ToolSignature.from_items(items1)
|
|
|
|
|
sig2 = ToolSignature.from_items(items2)
|
|
|
|
|
|
|
|
|
|
assert sig1.structure_hash != sig2.structure_hash
|
|
|
|
|
|
|
|
|
|
def test_pattern_detection_timestamp(self):
|
|
|
|
|
"""Timestamp-like fields are detected."""
|
|
|
|
|
items = [{"created_at": 1234567890, "updated_at": 1234567891}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.has_timestamp_like_field is True
|
|
|
|
|
|
|
|
|
|
def test_pattern_detection_status(self):
|
|
|
|
|
"""Status-like fields are detected."""
|
|
|
|
|
items = [{"status": "pending", "state": "active"}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.has_status_like_field is True
|
|
|
|
|
|
|
|
|
|
def test_pattern_detection_error(self):
|
|
|
|
|
"""Error-like fields are detected."""
|
|
|
|
|
items = [{"error": "Not found", "error_code": 404}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.has_error_like_field is True
|
|
|
|
|
|
|
|
|
|
def test_pattern_detection_message(self):
|
|
|
|
|
"""Message-like fields are detected."""
|
|
|
|
|
items = [{"message": "Success", "description": "Task completed"}]
|
|
|
|
|
|
|
|
|
|
sig = ToolSignature.from_items(items)
|
|
|
|
|
|
|
|
|
|
assert sig.has_message_like_field is True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestTelemetryCollector:
|
|
|
|
|
"""Test TelemetryCollector class."""
|
|
|
|
|
|
|
|
|
|
def test_record_compression(self):
|
|
|
|
|
"""Recording compression updates stats."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1", "name": "test"}, {"id": "2", "name": "test2"}]
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
stats = collector.get_stats()
|
|
|
|
|
assert stats["total_compressions"] == 1
|
|
|
|
|
assert stats["total_tokens_saved"] == 4500
|
|
|
|
|
|
|
|
|
|
def test_record_compression_disabled(self):
|
|
|
|
|
"""Disabled telemetry does not record."""
|
|
|
|
|
config = TelemetryConfig(enabled=False)
|
|
|
|
|
collector = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
stats = collector.get_stats()
|
|
|
|
|
assert stats["total_compressions"] == 0
|
|
|
|
|
|
|
|
|
|
def test_record_retrieval(self):
|
|
|
|
|
"""Recording retrieval updates stats."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
# First record a compression to create the signature
|
|
|
|
|
items = [{"id": "1", "name": "test"}]
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Get the signature hash
|
|
|
|
|
all_stats = collector.get_all_tool_stats()
|
|
|
|
|
sig_hash = list(all_stats.keys())[0]
|
|
|
|
|
|
|
|
|
|
# Record retrieval
|
|
|
|
|
collector.record_retrieval(
|
|
|
|
|
tool_signature_hash=sig_hash,
|
|
|
|
|
retrieval_type="full",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
stats = collector.get_stats()
|
|
|
|
|
assert stats["total_retrievals"] == 1
|
|
|
|
|
|
|
|
|
|
def test_tool_stats_aggregation(self):
|
|
|
|
|
"""Multiple compressions aggregate correctly."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1", "name": "test"}]
|
|
|
|
|
|
|
|
|
|
# Record 5 compressions
|
|
|
|
|
for i in range(5):
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10 + i, # Vary slightly
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500 + i * 10,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Check aggregation
|
|
|
|
|
all_stats = collector.get_all_tool_stats()
|
|
|
|
|
assert len(all_stats) == 1 # Same structure, same signature
|
|
|
|
|
|
|
|
|
|
sig_hash = list(all_stats.keys())[0]
|
|
|
|
|
tool_stats = all_stats[sig_hash]
|
|
|
|
|
assert tool_stats.total_compressions == 5
|
|
|
|
|
assert tool_stats.sample_size == 5
|
|
|
|
|
|
|
|
|
|
def test_different_tools_tracked_separately(self):
|
|
|
|
|
"""Different tool structures are tracked separately."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
# Tool A structure
|
|
|
|
|
items_a = [{"id": "1", "name": "test"}]
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items_a,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Tool B structure (different fields)
|
|
|
|
|
items_b = [{"code": 200, "result": {"data": "value"}}]
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items_b,
|
|
|
|
|
original_count=50,
|
|
|
|
|
compressed_count=5,
|
|
|
|
|
original_tokens=2500,
|
|
|
|
|
compressed_tokens=250,
|
|
|
|
|
strategy="smart_sample",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
all_stats = collector.get_all_tool_stats()
|
|
|
|
|
assert len(all_stats) == 2
|
|
|
|
|
|
|
|
|
|
def test_strategy_counts(self):
|
|
|
|
|
"""Strategy usage is tracked."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
|
|
|
|
|
# Different strategies
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="smart_sample",
|
|
|
|
|
)
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
all_stats = collector.get_all_tool_stats()
|
|
|
|
|
sig_hash = list(all_stats.keys())[0]
|
|
|
|
|
tool_stats = all_stats[sig_hash]
|
|
|
|
|
|
|
|
|
|
assert tool_stats.strategy_counts["top_n"] == 2
|
|
|
|
|
assert tool_stats.strategy_counts["smart_sample"] == 1
|
|
|
|
|
|
|
|
|
|
def test_recommendations_insufficient_samples(self):
|
|
|
|
|
"""No recommendations with insufficient samples."""
|
|
|
|
|
config = TelemetryConfig(min_samples_for_recommendation=10)
|
|
|
|
|
collector = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
for _ in range(5): # Less than 10
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
all_stats = collector.get_all_tool_stats()
|
|
|
|
|
sig_hash = list(all_stats.keys())[0]
|
|
|
|
|
|
|
|
|
|
recommendations = collector.get_recommendations(sig_hash)
|
|
|
|
|
assert recommendations is None
|
|
|
|
|
|
|
|
|
|
def test_recommendations_with_sufficient_samples(self):
|
|
|
|
|
"""Recommendations provided with sufficient samples."""
|
|
|
|
|
config = TelemetryConfig(min_samples_for_recommendation=5)
|
|
|
|
|
collector = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
for _ in range(10):
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
all_stats = collector.get_all_tool_stats()
|
|
|
|
|
sig_hash = list(all_stats.keys())[0]
|
|
|
|
|
|
|
|
|
|
recommendations = collector.get_recommendations(sig_hash)
|
|
|
|
|
assert recommendations is not None
|
|
|
|
|
assert "signature_hash" in recommendations
|
|
|
|
|
assert "confidence" in recommendations
|
|
|
|
|
|
|
|
|
|
def test_export_stats(self):
|
|
|
|
|
"""Export produces complete telemetry data."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1", "name": "test"}]
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
export = collector.export_stats()
|
|
|
|
|
|
|
|
|
|
assert "version" in export
|
|
|
|
|
assert "export_timestamp" in export
|
|
|
|
|
assert "summary" in export
|
|
|
|
|
assert "tool_stats" in export
|
|
|
|
|
assert export["summary"]["total_compressions"] == 1
|
|
|
|
|
|
|
|
|
|
def test_import_stats(self):
|
|
|
|
|
"""Import merges telemetry data."""
|
|
|
|
|
collector1 = TelemetryCollector()
|
|
|
|
|
collector2 = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
|
|
|
|
|
# Collector 1 records some compressions
|
|
|
|
|
for _ in range(5):
|
|
|
|
|
collector1.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Export from collector 1
|
|
|
|
|
export_data = collector1.export_stats()
|
|
|
|
|
|
|
|
|
|
# Collector 2 records different compressions
|
|
|
|
|
for _ in range(3):
|
|
|
|
|
collector2.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="smart_sample",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Import into collector 2
|
|
|
|
|
collector2.import_stats(export_data)
|
|
|
|
|
|
|
|
|
|
# Check merged data
|
|
|
|
|
all_stats = collector2.get_all_tool_stats()
|
|
|
|
|
sig_hash = list(all_stats.keys())[0]
|
|
|
|
|
tool_stats = all_stats[sig_hash]
|
|
|
|
|
|
|
|
|
|
assert tool_stats.sample_size == 8 # 5 + 3
|
|
|
|
|
|
|
|
|
|
def test_clear_resets_state(self):
|
|
|
|
|
"""clear() removes all telemetry data."""
|
|
|
|
|
collector = TelemetryCollector()
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
collector.clear()
|
|
|
|
|
|
|
|
|
|
stats = collector.get_stats()
|
|
|
|
|
assert stats["total_compressions"] == 0
|
|
|
|
|
assert stats["tool_signatures_tracked"] == 0
|
|
|
|
|
|
|
|
|
|
def test_field_distribution_analysis(self):
|
|
|
|
|
"""Field distributions are analyzed correctly."""
|
|
|
|
|
config = TelemetryConfig(include_field_distributions=True)
|
|
|
|
|
collector = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
items = [
|
|
|
|
|
{"id": "abc123", "score": 0.95, "tags": ["a", "b"]},
|
|
|
|
|
{"id": "xyz789", "score": 0.80, "tags": ["c"]},
|
|
|
|
|
{"id": "def456", "score": 0.70, "tags": ["d", "e", "f"]},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
collector.record_compression(
|
|
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=5000,
|
|
|
|
|
compressed_tokens=500,
|
|
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
export = collector.export_stats()
|
|
|
|
|
tool_stats_dict = list(export["tool_stats"].values())[0]
|
|
|
|
|
|
|
|
|
|
# Field distributions should be captured in events
|
|
|
|
|
# (Note: We don't store events in export by default, just stats)
|
|
|
|
|
assert tool_stats_dict["avg_compression_ratio"] > 0
|
|
|
|
|
|
|
|
|
|
def test_max_events_limit(self):
|
|
|
|
|
"""Events are limited to max_events_in_memory."""
|
|
|
|
|
config = TelemetryConfig(max_events_in_memory=5)
|
|
|
|
|
collector = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
|
|
|
|
|
# Record more than max events
|
|
|
|
|
for i in range(10):
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100 + i,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Events should be limited (internal detail)
|
|
|
|
|
assert len(collector._events) <= 5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestTelemetryPersistence:
|
|
|
|
|
"""Test telemetry persistence to disk."""
|
|
|
|
|
|
|
|
|
|
def test_save_and_load(self):
|
|
|
|
|
"""Save and load preserves telemetry data."""
|
|
|
|
|
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as f:
|
|
|
|
|
storage_path = f.name
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Create and populate collector
|
|
|
|
|
config = TelemetryConfig(storage_path=storage_path)
|
|
|
|
|
collector = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
items = [{"id": "1", "name": "test"}]
|
|
|
|
|
for _ in range(3):
|
|
|
|
|
collector.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
collector.save()
|
|
|
|
|
|
|
|
|
|
# Create new collector that loads from disk
|
|
|
|
|
collector2 = TelemetryCollector(config)
|
|
|
|
|
|
|
|
|
|
stats = collector2.get_stats()
|
|
|
|
|
assert stats["total_compressions"] == 3
|
|
|
|
|
|
|
|
|
|
finally:
|
|
|
|
|
os.unlink(storage_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestGlobalTelemetryCollector:
|
|
|
|
|
"""Test global telemetry collector singleton."""
|
|
|
|
|
|
|
|
|
|
def test_singleton_returns_same_instance(self):
|
|
|
|
|
"""get_telemetry_collector returns same instance."""
|
|
|
|
|
collector1 = get_telemetry_collector()
|
|
|
|
|
collector2 = get_telemetry_collector()
|
|
|
|
|
|
|
|
|
|
assert collector1 is collector2
|
|
|
|
|
|
|
|
|
|
def test_reset_clears_singleton(self):
|
|
|
|
|
"""reset_telemetry_collector creates new instance."""
|
|
|
|
|
collector1 = get_telemetry_collector()
|
|
|
|
|
items = [{"id": "1"}]
|
|
|
|
|
collector1.record_compression(
|
2026-01-10 15:33:44 -08:00
|
|
|
items=items,
|
|
|
|
|
original_count=100,
|
|
|
|
|
compressed_count=10,
|
|
|
|
|
original_tokens=1000,
|
|
|
|
|
compressed_tokens=100,
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
strategy="top_n",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
reset_telemetry_collector()
|
|
|
|
|
|
|
|
|
|
collector2 = get_telemetry_collector()
|
|
|
|
|
stats = collector2.get_stats()
|
|
|
|
|
assert stats["total_compressions"] == 0
|
|
|
|
|
|
|
|
|
|
def test_env_var_disables_telemetry(self, monkeypatch):
|
|
|
|
|
"""HEADROOM_TELEMETRY_DISABLED environment variable disables telemetry."""
|
|
|
|
|
reset_telemetry_collector()
|
|
|
|
|
monkeypatch.setenv("HEADROOM_TELEMETRY_DISABLED", "1")
|
|
|
|
|
|
|
|
|
|
collector = get_telemetry_collector()
|
|
|
|
|
|
|
|
|
|
assert collector._config.enabled is False
|
|
|
|
|
|
2026-05-05 11:30:10 -07:00
|
|
|
@pytest.mark.parametrize("off_value", ["off", "false", "0", "no", "disable", "disabled"])
|
|
|
|
|
def test_headroom_telemetry_off_disables_collector(self, monkeypatch, off_value):
|
|
|
|
|
"""HEADROOM_TELEMETRY=off (and other documented opt-out values) disables
|
|
|
|
|
the collector — closes #390.
|
|
|
|
|
|
|
|
|
|
Pre-#390 the collector only honoured HEADROOM_TELEMETRY_DISABLED, which
|
|
|
|
|
is undocumented. Users following the docs set HEADROOM_TELEMETRY=off and
|
|
|
|
|
watched /v1/telemetry continue to report enabled=true. The collector now
|
chore(telemetry): remove Supabase anonymous beacon; fix contact domain to headroomlabs.ai (#1526)
## Description
Removes the anonymous-telemetry **beacon** — the only external,
third-party data flow Headroom ever initiated. When telemetry was opted
in, it POSTed aggregate `/stats` to a hardcoded **Supabase** REST
endpoint (with an embedded anon API key in the source). For
enterprise/on-prem deployments this is exactly the kind of
vendor-controlled data egress a security review flags, so it's gone
entirely — **zero "Supabase" references remain in the codebase.**
What stays (by design): the **local** telemetry collector + the
`HEADROOM_TELEMETRY` opt-in (it only feeds `/stats` and `/v1/telemetry`
— nothing leaves the process), **OpenTelemetry export**
(`HEADROOM_OTEL_METRICS_*`, so operators send operational metrics to
*their own* collector), and the license usage reporter (your own domain,
license-key-gated).
Also fixes the contact domain: `headroom.dev` → `headroomlabs.ai`
everywhere.
Closes # (no tracking issue)
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [x] Code refactoring (no functional changes)
> Non-breaking: `HEADROOM_TELEMETRY` is still accepted (now gates local
collection only). The only behavior change is that no telemetry is ever
sent externally.
## Changes Made
- **Deleted the Supabase beacon**: `TelemetryBeacon` class,
`_SUPABASE_URL`/`_SUPABASE_KEY`/`_TABLE`/`_ENDPOINT`, the JSONB
projection helper, the proxy-lifespan beacon wiring, the `SUPABASE_`
install env passthrough, and `tests/test_strategy_stats_supabase.py`.
- **Kept** the local opt-in predicate (`is_telemetry_enabled` etc.) in
`beacon.py` — still used by the local collector + CLI — reworded to
"local only".
- **Retained** the single-worker-owner file lock (the cc-switch
reconciler depends on it); updated its comments to drop the beacon
framing.
- `/stats` `anon_telemetry_shipping` is now always `False` (nothing
ships externally); startup log reworded to "Local telemetry".
- Reworded remaining "Supabase" comments in `collector.py`,
`context.py`, `prometheus_metrics.py`, and two test docstrings.
- Contact domain: `security@headroom.dev` → `security@headroomlabs.ai`,
`conduct@headroom.dev` → `conduct@headroomlabs.ai`, FUNDING.yml sponsor
URL.
## Testing
- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check`)
- [x] Type checking passes (`mypy`)
- [x] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
$ grep -rniI "supabase" --include=*.py --include=*.md --include=*.mdx . # (excl .venv/sbom)
>>> ZERO Supabase references
$ grep -rniI "headroom.dev" .
>>> ZERO headroom.dev references
$ ruff check <changed files> -> All checks passed!
$ ruff format --check <changed files> -> 10 files already formatted
$ mypy <changed telemetry files> -> Success: no issues found
$ pytest tests/test_telemetry.py tests/test_telemetry_warning.py \
tests/test_proxy_telemetry_env.py tests/test_compression_observability.py \
tests/test_paths.py tests/test_paths_backward_compat.py -q
============================= 173 passed in 6.67s ==============================
```
## Real Behavior Proof
- **Environment:** macOS, Python 3.12 (`.venv`).
- **Exact command / steps:** repo-wide grep for
`supabase`/`headroom.dev`; `create_app(...)` driven through a full
`TestClient` lifespan (startup + shutdown) in
`test_proxy_telemetry_env.py`; `/stats` exercised in
`test_telemetry_warning.py`.
- **Observed result:** zero `supabase`/`headroom.dev` strings remain;
the proxy starts and shuts down cleanly with the beacon removed (the
worker-owner lock + reconciler still elect a single owner);
`/stats.anon_telemetry_shipping` is `False` even with
`HEADROOM_TELEMETRY=on`; local collector + OTEL paths unchanged.
- **Not tested:** no live network call was ever made (the point — the
external POST is gone). OTEL export and the license reporter were not
exercised (unchanged by this PR).
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable
## Additional Notes
- The license usage reporter (`reporter.py` → `app.headroomlabs.ai`) is
intentionally **kept** — it's license-key-gated (dormant for
unlicensed/OSS deployments) and goes to your own domain, not a third
party.
- Docs/CHANGELOG left unchecked: a couple of docs mention the telemetry
beacon and may want a follow-up note that it now collects locally only;
happy to add.
2026-06-27 22:48:26 -07:00
|
|
|
consults `is_telemetry_enabled()` (the documented opt-in predicate),
|
|
|
|
|
so both env vars take effect.
|
2026-05-05 11:30:10 -07:00
|
|
|
"""
|
|
|
|
|
reset_telemetry_collector()
|
|
|
|
|
monkeypatch.delenv("HEADROOM_TELEMETRY_DISABLED", raising=False)
|
|
|
|
|
monkeypatch.setenv("HEADROOM_TELEMETRY", off_value)
|
|
|
|
|
|
|
|
|
|
collector = get_telemetry_collector()
|
|
|
|
|
|
|
|
|
|
assert collector._config.enabled is False, (
|
|
|
|
|
f"HEADROOM_TELEMETRY={off_value!r} must disable the collector — "
|
|
|
|
|
"this is the documented opt-out path. If this assertion fails the "
|
|
|
|
|
"collector is silently ignoring the user's opt-out and /v1/telemetry "
|
|
|
|
|
"will report enabled=true even when telemetry is supposed to be off."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_headroom_telemetry_on_keeps_collector_enabled(self, monkeypatch):
|
fix(telemetry): switch anonymous telemetry to opt-in (off by default) (#1223)
## Description
Anonymous usage telemetry was **on by default** (opt-out). This flips it
to **opt-in**: nothing is collected or shipped unless the user
explicitly turns it on. Small change, but it makes "no data leaves the
proxy by default" the actual default rather than something users have to
discover and disable.
Closes # <!-- N/A: no tracking issue -->
## Type of Change
- [ ] Bug fix (non-breaking change that fixes an issue)
- [x] New feature (non-breaking change that adds functionality) — adds
`--telemetry` opt-in flag
- [x] Breaking change (fix or feature that would cause existing
functionality to change) — telemetry no longer runs unless opted in
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- `is_telemetry_enabled()` is now **fail-closed**: only explicit
on-values (`on`/`true`/`1`/`yes`/`enable`/`enabled`) enable telemetry;
unset, empty, or unrecognized values stay disabled. This single
predicate gates both the Supabase beacon and the local `/v1/telemetry`
collector.
- Added `--telemetry` opt-in flag to `headroom proxy` and `headroom
install apply`; kept `--no-telemetry` and `HEADROOM_TELEMETRY=off` for
back-compat. If both are passed, opt-out wins.
- Install manifests now write `HEADROOM_TELEMETRY` explicitly
(`on`/`off`) plus the matching flag, so generated systemd/docker/launchd
deployments are unambiguous and don't rely on the runtime default.
- Startup banner and proxy log show `DISABLED` by default and surface
how to opt in.
- Updated tests for opt-in defaults; added coverage for the default-off
banner, the `--telemetry` flag, and the explicit-on manifest path.
- Updated docs
(proxy/configuration/installation/benchmarks/community-savings mdx, spec
011/015, wiki proxy/cli/benchmarks/metrics) and `CHANGELOG.md`.
## Testing
- [x] Unit tests pass (`pytest`) — targeted telemetry + install-planner
suites
- [x] Linting passes (`ruff check`)
- [x] Type checking passes (`mypy`)
- [x] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
$ python -m pytest tests/test_telemetry_warning.py tests/test_telemetry.py tests/test_install/test_planner.py -q
81 passed
$ ruff check <changed source + test files>
All checks passed!
$ mypy headroom/telemetry/beacon.py headroom/cli/proxy.py headroom/cli/install.py \
headroom/install/planner.py headroom/proxy/server.py
Success: no issues found in 5 source files
```
## Real Behavior Proof
- **Environment:** macOS (darwin 25.4.0), project `.venv`, `headroom`
CLI.
- **Exact command / steps:**
```
$ python -c "import os; from headroom.telemetry.beacon import
is_telemetry_enabled; \
os.environ.pop('HEADROOM_TELEMETRY', None); print('unset ->',
is_telemetry_enabled()); \
[ (os.environ.__setitem__('HEADROOM_TELEMETRY', v), print(repr(v), '->',
is_telemetry_enabled())) \
for v in ['on','TRUE','1','yes','off','0','garbage',''] ]"
$ headroom proxy --help | grep -i telemetry
$ headroom install apply --help | grep -i telemetry
```
- **Observed result:**
```
unset -> False # off by default
'on' -> True 'TRUE' -> True '1' -> True 'yes' -> True
'off' -> False '0' -> False
'garbage' -> False '' -> False # fail-closed
proxy: --telemetry Opt in to anonymous usage telemetry — off by default
(env: HEADROOM_TELEMETRY=on)
--no-telemetry Force anonymous usage telemetry off (already the default;
env: HEADROOM_TELEMETRY=off)
install: --telemetry Opt in to anonymous telemetry in the runtime (off
by default).
--no-telemetry Force anonymous telemetry off in the runtime (already the
default).
```
- **Not tested:** live Supabase beacon network round-trip (no opt-in
network call was made); full `pytest` suite was not run — only the
telemetry + install-planner targeted suites.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have updated the CHANGELOG.md if applicable
## Additional Notes
- "Breaking change" is checked because the default behavior changes
(telemetry stops running unless opted in). It is **not** an API break —
`--no-telemetry` and `HEADROOM_TELEMETRY=off` still work, so existing
opt-out configs are unaffected.
- No tracking issue, so `Closes #` is left N/A.
2026-06-20 21:26:04 -07:00
|
|
|
"""Sanity check: the explicit opt-in path (HEADROOM_TELEMETRY=on) leaves
|
|
|
|
|
the collector enabled. Telemetry is off by default, so this requires the
|
|
|
|
|
user to have turned it on."""
|
2026-05-05 11:30:10 -07:00
|
|
|
reset_telemetry_collector()
|
|
|
|
|
monkeypatch.delenv("HEADROOM_TELEMETRY_DISABLED", raising=False)
|
|
|
|
|
monkeypatch.setenv("HEADROOM_TELEMETRY", "on")
|
|
|
|
|
|
|
|
|
|
collector = get_telemetry_collector()
|
|
|
|
|
|
|
|
|
|
assert collector._config.enabled is True
|
|
|
|
|
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
|
|
|
|
|
class TestRetrievalStatsModel:
|
|
|
|
|
"""Test RetrievalStats data model."""
|
|
|
|
|
|
|
|
|
|
def test_retrieval_rate_calculation(self):
|
|
|
|
|
"""Retrieval rate is calculated correctly."""
|
|
|
|
|
stats = RetrievalStats(
|
|
|
|
|
tool_signature_hash="abc123",
|
|
|
|
|
total_compressions=100,
|
|
|
|
|
total_retrievals=30,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert stats.retrieval_rate == 0.3
|
|
|
|
|
|
|
|
|
|
def test_retrieval_rate_zero_compressions(self):
|
|
|
|
|
"""Retrieval rate is 0 when no compressions."""
|
|
|
|
|
stats = RetrievalStats(
|
|
|
|
|
tool_signature_hash="abc123",
|
|
|
|
|
total_compressions=0,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert stats.retrieval_rate == 0.0
|
|
|
|
|
|
|
|
|
|
def test_full_retrieval_rate_calculation(self):
|
|
|
|
|
"""Full retrieval rate is calculated correctly."""
|
|
|
|
|
stats = RetrievalStats(
|
|
|
|
|
tool_signature_hash="abc123",
|
|
|
|
|
total_retrievals=20,
|
|
|
|
|
full_retrievals=15,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert stats.full_retrieval_rate == 0.75
|
|
|
|
|
|
|
|
|
|
def test_to_dict(self):
|
|
|
|
|
"""to_dict includes derived properties."""
|
|
|
|
|
stats = RetrievalStats(
|
|
|
|
|
tool_signature_hash="abc123",
|
|
|
|
|
total_compressions=100,
|
|
|
|
|
total_retrievals=50,
|
|
|
|
|
full_retrievals=40,
|
|
|
|
|
search_retrievals=10,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
d = stats.to_dict()
|
|
|
|
|
|
|
|
|
|
assert d["retrieval_rate"] == 0.5
|
|
|
|
|
assert d["full_retrieval_rate"] == 0.8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestAnonymizedToolStats:
|
|
|
|
|
"""Test AnonymizedToolStats data model."""
|
|
|
|
|
|
|
|
|
|
def test_to_dict(self):
|
|
|
|
|
"""to_dict serializes all fields."""
|
|
|
|
|
sig = ToolSignature(
|
|
|
|
|
structure_hash="abc123",
|
|
|
|
|
field_count=3,
|
|
|
|
|
has_nested_objects=False,
|
|
|
|
|
has_arrays=False,
|
|
|
|
|
max_depth=1,
|
|
|
|
|
)
|
|
|
|
|
stats = AnonymizedToolStats(
|
|
|
|
|
signature=sig,
|
|
|
|
|
total_compressions=100,
|
|
|
|
|
total_items_seen=10000,
|
|
|
|
|
total_items_kept=500,
|
|
|
|
|
avg_compression_ratio=0.05,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
d = stats.to_dict()
|
|
|
|
|
|
|
|
|
|
assert d["signature"]["structure_hash"] == "abc123"
|
|
|
|
|
assert d["total_compressions"] == 100
|
|
|
|
|
assert d["avg_compression_ratio"] == 0.05
|
|
|
|
|
|
|
|
|
|
def test_from_dict(self):
|
|
|
|
|
"""from_dict deserializes correctly."""
|
|
|
|
|
data = {
|
|
|
|
|
"signature": {
|
|
|
|
|
"structure_hash": "xyz789",
|
|
|
|
|
"field_count": 5,
|
|
|
|
|
"has_nested_objects": True,
|
|
|
|
|
"has_arrays": False,
|
|
|
|
|
"max_depth": 2,
|
|
|
|
|
},
|
|
|
|
|
"total_compressions": 50,
|
|
|
|
|
"sample_size": 50,
|
|
|
|
|
"confidence": 0.5,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stats = AnonymizedToolStats.from_dict(data)
|
|
|
|
|
|
|
|
|
|
assert stats.signature.structure_hash == "xyz789"
|
|
|
|
|
assert stats.total_compressions == 50
|
|
|
|
|
assert stats.confidence == 0.5
|
|
|
|
|
|
|
|
|
|
def test_from_dict_does_not_mutate_input(self):
|
|
|
|
|
"""from_dict does not modify the input dictionary."""
|
|
|
|
|
data = {
|
|
|
|
|
"signature": {
|
|
|
|
|
"structure_hash": "abc123",
|
|
|
|
|
"field_count": 3,
|
|
|
|
|
"has_nested_objects": False,
|
|
|
|
|
"has_arrays": False,
|
|
|
|
|
"max_depth": 1,
|
|
|
|
|
},
|
|
|
|
|
"total_compressions": 10,
|
|
|
|
|
"strategy_counts": {"top_n": 5, "smart_sample": 5},
|
|
|
|
|
"recommended_preserve_fields": ["field1", "field2"],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Make a deep copy to compare after
|
|
|
|
|
import copy
|
2026-01-10 15:33:44 -08:00
|
|
|
|
feat: Add CCR architecture, TOIN telemetry, and DevEx improvements
## Core Features
### Compress-Cache-Retrieve (CCR) Architecture
- Implement reversible compression with automatic retrieval support
- Add CompressionStore for caching original content with TTL-based eviction
- Add CompressionFeedback for learning from retrieval patterns
- Implement tool injection for LLM retrieval capability
- Add MCP server support for CCR operations
- Track retrieval rates to dynamically adjust compression aggressiveness
### Tool Output Intelligence Network (TOIN)
- Implement cross-session pattern learning for tool compression
- Add ToolSignature for structural hashing of tool outputs
- Track compression success rates per strategy (top_n, sample, truncate, etc.)
- Implement privacy-preserving telemetry with SHA256 hashing
- Add persistent storage with JSON file backend
- Support network-effect learning across tool types
### SmartCrusher Enhancements
- Add crushability analysis with variance/uniqueness detection
- Implement statistical anomaly detection for outlier preservation
- Add relevance-based item prioritization using BM25 scoring
- Support multiple compression strategies with quality retention
- Add change point detection for time-series data
- Implement constant factoring for homogeneous datasets
## Developer Experience Improvements
### Exception Hierarchy
- Add HeadroomError base class for all custom exceptions
- Add specific exceptions: ConfigurationError, ProviderError,
StorageError, CompressionError, TokenizationError, CacheError,
ValidationError, TransformError
### Client Enhancements
- Add validate_setup() for configuration verification
- Add get_stats() for in-memory session metrics without DB query
- Track session statistics (requests, tokens saved, cache hits)
### Logging Infrastructure
- Add structured logging to TransformPipeline with token savings
- Add logging to RollingWindow for dropped message tracking
- Add logging to ToolCrusher for compression events
- Add logging to CacheAligner for cache hit/miss detection
- Add logging to SmartCrusher for strategy selection
## Bug Fixes (from deep analysis)
### Critical Fixes
- Fix eviction heap memory leak with stale entry tracking
- Fix hash collision detection in compression store
- Fix strategy truncation desync in TOIN
- Fix non-deterministic set truncation with sorted iteration
- Fix race conditions in lazy initialization with proper locking
- Fix user count double-counting in TOIN metrics
### High Priority Fixes
- Fix unbounded strategy_success_rates growth with LRU eviction
- Fix mutable pattern references with defensive copying
- Fix lock held during file I/O with copy-then-write pattern
- Fix state divergence on eviction with success event recording
- Fix TOIN skip check order for CPU efficiency
- Fix preserve_fields type mismatch (set vs list)
- Fix prioritize_indices exceeding max_items limit
- Fix instance ID collision risk (32-bit to 64-bit hash)
## Testing
- Add comprehensive test suites for CCR, TOIN, and telemetry
- Add crushability detection tests
- Add quality retention tests for compression
- Add integration tests for cross-component data flow
- All 902 tests passing
2026-01-10 10:12:13 -08:00
|
|
|
original_data = copy.deepcopy(data)
|
|
|
|
|
|
|
|
|
|
stats = AnonymizedToolStats.from_dict(data)
|
|
|
|
|
|
|
|
|
|
# Modify the stats object
|
|
|
|
|
stats.strategy_counts["new_strategy"] = 10
|
|
|
|
|
stats.recommended_preserve_fields.append("field3")
|
|
|
|
|
|
|
|
|
|
# Original data should be unchanged
|
|
|
|
|
assert data == original_data
|
|
|
|
|
assert "new_strategy" not in data["strategy_counts"]
|
|
|
|
|
assert "field3" not in data["recommended_preserve_fields"]
|