From 535cd136650d0753d218d1c1e2d24e06eb33ff8a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 16 Jul 2026 13:36:39 +0100 Subject: [PATCH] Expose the repository readiness join --- .../src/bin/epiphany-memory-semantic.rs | 60 ++++++++++++++++++- epiphany-core/src/lib.rs | 6 +- .../src/workspace_coverage_projector.rs | 25 +++++--- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/epiphany-core/src/bin/epiphany-memory-semantic.rs b/epiphany-core/src/bin/epiphany-memory-semantic.rs index 67d3b251..31bf8050 100644 --- a/epiphany-core/src/bin/epiphany-memory-semantic.rs +++ b/epiphany-core/src/bin/epiphany-memory-semantic.rs @@ -1,9 +1,10 @@ use anyhow::{Context, Result, anyhow}; use epiphany_core::{ EpiphanyMemoryContextQuery, EpiphanyMemoryGraphSnapshot, MemorySemanticIndexConfig, - MemorySemanticProjectionInput, SemanticPartition, agent_memory_semantic_projection_input, + MemorySemanticProjectionInput, SemanticPartition, WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, + WorkspaceCoveragePolicy, WorkspaceProjectionIdentity, agent_memory_semantic_projection_input, load_memory_graph_snapshot, load_memory_semantic_projection_readiness, - publish_epiphany_cultmesh_semantic_projection_health, + observe_repository_readiness, publish_epiphany_cultmesh_semantic_projection_health, runtime_modeling_semantic_projection_input, semantic_memory_context, }; use std::env; @@ -62,6 +63,42 @@ fn main() -> Result<()> { ); print_json(&packet)?; } + "repository-readiness" => { + let runtime_store = options.runtime_store.as_ref().ok_or_else(|| { + usage_error("repository-readiness requires --runtime-store ") + })?; + if options.graph_store.is_some() || options.agent_store.is_some() { + return Err(usage_error( + "repository-readiness accepts only --runtime-store ", + )); + } + let workspace_identity = WorkspaceProjectionIdentity { + policy: WorkspaceCoveragePolicy::bounded_regular_files_v0( + WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, + )?, + qdrant_url: config.qdrant_url.clone(), + qdrant_api_key: config.qdrant_api_key.clone(), + qdrant_timeout_ms: config.qdrant_timeout_ms, + embedding_provider_id: options.workspace_embedding_provider_id.clone().ok_or_else( + || { + usage_error( + "repository-readiness requires --workspace-embedding-provider-id ", + ) + }, + )?, + embedding_model: options.workspace_embedding_model.clone().ok_or_else(|| { + usage_error("repository-readiness requires --workspace-embedding-model ") + })?, + vector_dimensions: options.workspace_vector_dimensions.ok_or_else(|| { + usage_error("repository-readiness requires --workspace-vector-dimensions ") + })?, + }; + print_json(&observe_repository_readiness( + runtime_store, + &config, + &workspace_identity, + )?)?; + } _ => return Err(usage_error(&format!("unknown command {command:?}"))), } Ok(()) @@ -80,6 +117,9 @@ struct Options { query_id: Option, budget: Option, profile: Option, + workspace_embedding_provider_id: Option, + workspace_embedding_model: Option, + workspace_vector_dimensions: Option, } impl Options { @@ -97,6 +137,9 @@ impl Options { query_id: None, budget: None, profile: None, + workspace_embedding_provider_id: None, + workspace_embedding_model: None, + workspace_vector_dimensions: None, }; let mut args = args.peekable(); while let Some(flag) = args.next() { @@ -117,6 +160,17 @@ impl Options { "--query-id" => options.query_id = Some(value()?), "--budget" => options.budget = Some(value()?.parse().context("invalid budget")?), "--profile" => options.profile = Some(parse_profile(&value()?)?), + "--workspace-embedding-provider-id" => { + options.workspace_embedding_provider_id = Some(value()?) + } + "--workspace-embedding-model" => options.workspace_embedding_model = Some(value()?), + "--workspace-vector-dimensions" => { + options.workspace_vector_dimensions = Some( + value()? + .parse() + .context("invalid workspace vector dimensions")?, + ) + } _ => return Err(usage_error(&format!("unexpected argument {flag:?}"))), } } @@ -221,7 +275,7 @@ fn parse_profile(value: &str) -> Result { fn usage_error(message: &str) -> anyhow::Error { anyhow!( - "{message}\nusage: epiphany-memory-semantic (--runtime-store |--agent-store |--graph-store ) [--swarm-id ] --partition [--local-verse-store --runtime-id --provider-incarnation ] [--text ] [--query-id ] [--budget ] [--profile ]" + "{message}\nusage: epiphany-memory-semantic (--runtime-store |--agent-store |--graph-store ) [--swarm-id ] --partition [--local-verse-store --runtime-id --provider-incarnation ] [--text ] [--query-id ] [--budget ] [--profile ] [--workspace-embedding-provider-id --workspace-embedding-model --workspace-vector-dimensions ]" ) } diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index ae0251b8..e8a3d8d8 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -1196,9 +1196,9 @@ pub use workspace_coverage_process_documents::{ write_workspace_coverage_provider_heartbeat, }; pub use workspace_coverage_projector::{ - WorkspaceCoverageRecoveryOutcome, WorkspaceCoverageRecoveryTarget, - authenticate_workspace_coverage_recovery_receipt, current_workspace_coverage_recovery_target, - recover_workspace_coverage_projection, + WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, WorkspaceCoverageRecoveryOutcome, + WorkspaceCoverageRecoveryTarget, authenticate_workspace_coverage_recovery_receipt, + current_workspace_coverage_recovery_target, recover_workspace_coverage_projection, }; pub use workspace_coverage_projector_service::WorkspaceCoverageProjectorConfig; pub use workspace_coverage_projector_service::WorkspaceCoverageProjectorPulseStatus; diff --git a/epiphany-core/src/workspace_coverage_projector.rs b/epiphany-core/src/workspace_coverage_projector.rs index f5bddfda..95e8970e 100644 --- a/epiphany-core/src/workspace_coverage_projector.rs +++ b/epiphany-core/src/workspace_coverage_projector.rs @@ -42,7 +42,7 @@ const RECOVERY_TYPE: &str = "gamecult.epiphany.workspace_coverage_recovery_recei const RECOVERY_SCHEMA: &str = "gamecult.epiphany.workspace_coverage_recovery_receipt.v0"; const PROJECTION_SCHEMA: &str = "gamecult.epiphany.workspace_bytes_projection.v0"; const CHUNKER_ID: &str = "utf8_lines_96_overlap_8_v0"; -const MAXIMUM_FILE_BYTES: u64 = 4 * 1024 * 1024; +pub const WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES: u64 = 4 * 1024 * 1024; const CHUNK_LINES: usize = 96; const CHUNK_OVERLAP_LINES: usize = 8; const RECEIPT_TYPE: &str = "gamecult.epiphany.workspace_coverage_receipt"; @@ -803,7 +803,8 @@ pub(crate) fn classify_current_workspace_coverage( .ok_or_else(|| anyhow!("current workspace coverage head names a missing receipt"))?, )?; validate_workspace_coverage_head(&obligation, &plan, &receipt, &head)?; - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0(MAXIMUM_FILE_BYTES)?; + let policy = + WorkspaceCoveragePolicy::bounded_regular_files_v0(WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES)?; let policy_sha256 = format!( "{:x}", Sha256::digest(rmp_serde::to_vec_named(&policy).map_err(|error| anyhow!(error))?) @@ -994,7 +995,8 @@ pub(crate) fn prepare_workspace_coverage_projection( vector_dimensions: u32, ) -> Result { let basis = body.basis(); - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0(MAXIMUM_FILE_BYTES)?; + let policy = + WorkspaceCoveragePolicy::bounded_regular_files_v0(WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES)?; let raw_obligation = derive_workspace_coverage_obligation_from_authenticated_manifest( basis, body.manifest(), @@ -2442,7 +2444,9 @@ mod tests { inputs, &mut projection, )?; - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0(MAXIMUM_FILE_BYTES)?; + let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( + WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, + )?; let evidence = observe_current_workspace_coverage_evidence( &runtime, @@ -2462,8 +2466,9 @@ mod tests { ); assert!(evidence.head_envelope_digest.starts_with("sha256-")); - let wrong_policy = - WorkspaceCoveragePolicy::bounded_regular_files_v0(MAXIMUM_FILE_BYTES - 1)?; + let wrong_policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( + WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES - 1, + )?; assert!( observe_current_workspace_coverage_evidence( &runtime, @@ -2490,7 +2495,9 @@ mod tests { classify_current_workspace_coverage(&runtime, &basis, "provider", "model", 3)?, WorkspaceCoverageCurrentState::Current(_) )); - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0(MAXIMUM_FILE_BYTES)?; + let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( + WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, + )?; let mut missing_live_collection = FakeProjectionPort::new(Hostility::Honest); missing_live_collection.collection_present = false; @@ -2572,7 +2579,9 @@ mod tests { inner: projection, body_store, }; - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0(MAXIMUM_FILE_BYTES)?; + let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( + WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, + )?; assert!( observe_current_workspace_coverage_evidence( &runtime,