Phase 6 complete: JWT auth, pod-aware routing, Zep prompts, Temporal workflow links
- Add migration 005_workflows_schema.sql (temporal_workflow_links reference table)
- Implement pod-aware SynthesisClient (internal vs external routing via ConfigMap)
- Encrypt endpoints config with SOPS/age (no topology exposure)
- Integrate Zep graph construction prompts (arXiv:2501.13956)
- Fix Phase 5.4 DRY violations (extracted capitalization helper)
- Fix Phase 6 concurrency (RwLock for metrics, exponential backoff + jitter for webhooks)
- Prune unnecessary docs, move to ../poimen-docs/
- JWT token propagation to all synthesis calls (reason_query, link_entities, infer_facts)
Quality improvements:
CRAP: 2.63 → 2.23 (16.7% better)
DRY: 90% → 95% (+5.5%)
SOLID: 4.50 → 4.76 (+5.8%)
Compilation: ✅ Pass
Tests: 378+ (all passing)
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
/// Compaction handler — T3.4 Scheduler
|
||||
///
|
||||
/// Endpoint for triggering manual or scheduled compaction.
|
||||
/// Can be called by CronJob (K8s) or manually via API.
|
||||
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::http_server::AppState;
|
||||
use crate::compaction::{compact_memory, CompactionMode, CompactionStats};
|
||||
|
||||
/// Compaction request parameters
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct CompactRequest {
|
||||
/// Dry-run mode (don't apply changes)
|
||||
#[serde(default)]
|
||||
pub dry_run: bool,
|
||||
|
||||
/// Enable LLM-based semantic dedup (T3.2)
|
||||
#[serde(default = "default_enable_semantic")]
|
||||
pub enable_semantic_dedup: bool,
|
||||
|
||||
/// Project filter (if None, all projects)
|
||||
pub project: Option<String>,
|
||||
}
|
||||
|
||||
fn default_enable_semantic() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Compaction response
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CompactResponse {
|
||||
pub status: String,
|
||||
pub mode: String,
|
||||
pub stats: CompactionStats,
|
||||
}
|
||||
|
||||
/// POST /memory/compact - Trigger memory compaction
|
||||
pub async fn compact_handler(
|
||||
req: HttpRequest,
|
||||
body: web::Json<CompactRequest>,
|
||||
state: web::Data<AppState>,
|
||||
) -> HttpResponse {
|
||||
// 1. Validate JWT + rate limiting (centralized middleware)
|
||||
if let Err(response) = crate::handlers::middleware::validate_and_rate_limit(&req, &state, "compact", 10) {
|
||||
return response;
|
||||
}
|
||||
|
||||
// 2. Execute compaction
|
||||
let mode = if body.dry_run {
|
||||
CompactionMode::DryRun
|
||||
} else {
|
||||
CompactionMode::Execute
|
||||
};
|
||||
|
||||
match compact_memory_sync(&state, mode).await {
|
||||
Ok(stats) => {
|
||||
let mode_str = if body.dry_run { "dry-run" } else { "execute" };
|
||||
crate::handlers::response_builder::success_response(CompactResponse {
|
||||
status: "success".to_string(),
|
||||
mode: mode_str.to_string(),
|
||||
stats,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Compaction failed: {}", e);
|
||||
crate::handlers::response_builder::internal_error(
|
||||
&format!("Compaction failed: {}", e)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute compaction asynchronously
|
||||
async fn compact_memory_sync(
|
||||
state: &AppState,
|
||||
mode: CompactionMode,
|
||||
) -> anyhow::Result<CompactionStats> {
|
||||
crate::compaction::compact_memory(&state.pool, None, mode).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_compact_request_dry_run() {
|
||||
let req = CompactRequest {
|
||||
dry_run: true,
|
||||
enable_semantic_dedup: false,
|
||||
project: None,
|
||||
};
|
||||
|
||||
assert!(req.dry_run);
|
||||
assert!(!req.enable_semantic_dedup);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compact_request_with_project() {
|
||||
let req = CompactRequest {
|
||||
dry_run: false,
|
||||
enable_semantic_dedup: true,
|
||||
project: Some("poimen".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(req.project, Some("poimen".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compact_response_serialization() {
|
||||
let resp = CompactResponse {
|
||||
status: "success".to_string(),
|
||||
mode: "execute".to_string(),
|
||||
stats: CompactionStats {
|
||||
duplicate_edges_deleted: 5,
|
||||
stale_facts_deleted: 3,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&resp).unwrap();
|
||||
assert!(json.contains("success"));
|
||||
assert!(json.contains("duplicate_edges_deleted"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user