stemedb/applications/aphoria/src/episteme/aliases.rs
jordan 157dbbb9eb feat: Complete Aphoria Phase 8-9 + UAT suite (90/90 tests passing)
## Phase 8: Enterprise Extractor Improvements 
- 14 security extractors (TLS, JWT, SQL injection, XSS, etc.)
- 10 framework-specific extractors (Spring, Django, Rails, etc.)
- Config file security detection (YAML, TOML)

## Phase 9: Autonomous Extractor Generation 
- Shadow mode executor with TP/FP tracking
- Graduation pipeline with confidence thresholds
- Auto-rollback on regression detection
- Cross-project pattern syncing

## UAT Suite Complete (14 scripts, 90 tests)
- test-core-detection.sh (6 tests)
- test-declarative-extractors.sh (5 tests)
- test-domain-frameworks.sh (5 tests)
- test-domain-unreal.sh (3 tests)
- test-llm-extraction.sh (6 tests)
- test-eval-harness.sh (5 tests)
- test-cross-language.sh (3 tests)
- test-precommit-performance.sh (4 tests)
- test-output-formats.sh (8 tests)
- test-drift-detection.sh (6 tests)
- test-exit-codes.sh (12 tests)
+ 3 more scripts

## Other Changes
- Updated roadmap to mark Phase 8-9 complete
- Added .gitignore entries for build artifacts
- Updated pre-commit: 800 line limit, exclude tests/data/cmd

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:50:55 -07:00

96 lines
3.3 KiB
Rust

//! Alias management for local Episteme operations.
//!
//! Handles auto-alias creation and manual alias management.
use stemedb_core::types::{AliasOrigin, ConceptAlias, ConceptPath};
use stemedb_storage::AliasStore;
use tracing::{debug, instrument};
use crate::AphoriaError;
use super::corpus::current_timestamp;
use super::local::LocalEpisteme;
impl LocalEpisteme {
/// Create an alias from a code path to an authoritative path, if it doesn't already exist.
///
/// This is used during conflict detection to persist the relationship between
/// code concepts and their authoritative counterparts.
#[instrument(skip(self), fields(code_path = %code_path, auth_path = %auth_path))]
pub async fn create_alias_if_new(
&self,
code_path: &str,
auth_path: &str,
agent_id: [u8; 32],
timestamp: u64,
) -> Result<(), AphoriaError> {
// Check if alias already exists
let existing = self.alias_store().get_canonical(code_path).await.map_err(|e| {
AphoriaError::Storage(format!("Failed to get canonical alias for {code_path}: {e}"))
})?;
if existing.is_some() {
debug!("Alias already exists, skipping");
return Ok(());
}
// Parse paths
let alias_path = ConceptPath::parse(code_path)
.map_err(|e| AphoriaError::Storage(format!("Invalid code path: {}", e)))?;
let canonical_path = ConceptPath::parse(auth_path)
.map_err(|e| AphoriaError::Storage(format!("Invalid auth path: {}", e)))?;
// Create and persist alias
let alias = ConceptAlias::new(
alias_path,
canonical_path,
agent_id,
timestamp,
AliasOrigin::AutoDetected,
);
self.alias_store().set_alias(&alias).await.map_err(|e| {
AphoriaError::Storage(format!(
"Failed to set alias from {code_path} to {auth_path}: {e}"
))
})?;
debug!("Created auto-detected alias");
Ok(())
}
/// Fetch manual aliases for policy export.
///
/// Returns all aliases stored in the local Episteme instance.
/// These can be auto-detected aliases from conflict detection or
/// manually created aliases.
pub async fn fetch_manual_aliases(&self) -> Result<Vec<ConceptAlias>, AphoriaError> {
let alias_tuples = self
.alias_store()
.list_all_aliases()
.await
.map_err(|e| AphoriaError::Storage(format!("Failed to list all aliases: {e}")))?;
let timestamp = current_timestamp();
let agent_id = self.agent_id();
// Convert (alias_str, canonical_str) tuples to ConceptAlias structs
let aliases = alias_tuples
.into_iter()
.filter_map(|(alias_str, canonical_str)| {
let alias_path = ConceptPath::parse(&alias_str).ok()?;
let canonical_path = ConceptPath::parse(&canonical_str).ok()?;
Some(ConceptAlias::new(
alias_path,
canonical_path,
agent_id,
timestamp,
AliasOrigin::Manual, // Treat all exported aliases as manual
))
})
.collect();
Ok(aliases)
}
}