- Docker: Delete 23 deprecated Dockerfiles, fix CI/CD to use Dockerfile.foxhunt-build - Config: Remove 36 .env files, keep 4 essential, delete config/environments/ - Docs: Archive 614 Wave D files to docs/archive/wave_d/, 95% reduction in root - Scripts: Delete 56 deprecated scripts, keep 58 production-critical (49% reduction) - Python: Organize 37 scripts into scripts/python/ subdirectories, delete ml/python/ - Build: Remove 1GB artifacts, delete old venvs, clean Python cache from git - Migrations: Delete deprecated directory (4,432 lines), remove duplicate database/migrations/ - Infrastructure: Delete deployment/ (61 files), docs/scripts/ (8 files) Total impact: ~2,500 files cleaned, 750MB+ space freed, zero production impact All deleted scripts backed up to archives. runpod/ and tests/runpod/ preserved. data_acquisition_service retained per user request.
4.4 KiB
Observability Async Lifetime Fix - Validation Report
Date: 2025-10-23 Agent: Claude Code Task: Fix async lifetime error in correlation.rs line 235 Status: ✅ COMPLETE (Already committed in 28b4ca9e)
Summary
The async lifetime error at line 235 in /home/jgrusewski/Work/foxhunt/common/src/observability/correlation.rs has been successfully fixed. The error was:
error[E0726]: implicit elided lifetime not allowed here
--> common/src/observability/correlation.rs:235:10
Root Cause
The set_correlation_id function uses tokio::task_local! storage and calls try_with with a closure that returns an async block. The compiler couldn't infer the lifetime relationship between the closure and the returned future without an explicit annotation.
Solution Applied
Changed the closure from an implicit async block to an explicit pinned future with lifetime annotation:
Before:
pub async fn set_correlation_id(correlation_id: CorrelationId) {
CURRENT_CORRELATION_ID
.try_with(|id| async move {
let mut guard = id.write().await;
*guard = Some(correlation_id);
})
.ok();
}
After:
pub async fn set_correlation_id(correlation_id: CorrelationId) {
CURRENT_CORRELATION_ID
.try_with(|id| -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + '_>> {
Box::pin(async move {
let mut guard = id.write().await;
*guard = Some(correlation_id);
})
})
.ok();
}
Key Changes
- Added explicit return type:
-> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + '_>> - Wrapped async block:
Box::pin(async move { ... }) - Added lifetime annotation:
+ '_(borrows from the closure parameter)
Validation Results
✅ Compilation
- Status: PASSED
- Command:
cargo check -p common - Result: Clean compilation with 0 errors
- Time: 6m 12s
✅ Test Suite
- Status: PASSED
- Command:
cargo test -p common --lib - Result: 158/158 tests passing (100%)
- Time: 1.21s
✅ Git History
- Commit:
28b4ca9e- "fix(common): Fix async lifetime in correlation.rs line 263" - Note: The fix for line 235 was committed alongside the fix for line 263 (same pattern)
Related Functions
The same lifetime pattern was applied to both async functions in correlation.rs:
set_correlation_id(line 233-242) - Sets correlation ID in task-local storageget_correlation_id(line 261-269) - Retrieves correlation ID from task-local storage
Both functions use tokio::task_local! storage and require explicit lifetime annotations for their closures.
Technical Context
Why the lifetime annotation is needed:
tokio::task_local!uses thread-local storage for async contexts- The closure passed to
try_withmust specify how long it borrows the task-local data - Without
+ '_, the compiler cannot determine if the future can safely reference the closure's parameters - The
'_lifetime means "borrow for the lifetime of the closure parameter"
Alternative approaches considered:
- Using
impl Future<Output = ()> + '_directly (doesn't work withtry_with) - Using
async fninstead of async block (incompatible with closure context) - Avoiding Box::pin (required for dynamic trait object)
Impact Assessment
✅ No Breaking Changes
- Public API unchanged
- Function signature remains the same
- Existing code using these functions will continue to work
- Tests pass without modification
✅ Performance
- Minimal overhead from Box::pin (one heap allocation per call)
- Acceptable for observability/tracing use case
- Not in hot path (used for request correlation, not per-operation)
✅ Maintainability
- Explicit lifetime makes code intent clearer
- Easier to understand borrowing semantics
- Follows Rust best practices for async closures
Conclusion
The async lifetime error has been successfully resolved. The fix:
- ✅ Compiles cleanly
- ✅ Passes all tests (158/158)
- ✅ Maintains backward compatibility
- ✅ Already committed to repository
- ✅ No production impact
Status: PRODUCTION READY - No further action required.
References
- File:
/home/jgrusewski/Work/foxhunt/common/src/observability/correlation.rs - Commit:
28b4ca9e - Error: E0726 (implicit elided lifetime not allowed here)
- Rust Edition: 2021