Expose the repository readiness join

This commit is contained in:
Meta Vens 2026-07-16 13:36:39 +01:00
commit 535cd13665
3 changed files with 77 additions and 14 deletions

View file

@ -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 <path>")
})?;
if options.graph_store.is_some() || options.agent_store.is_some() {
return Err(usage_error(
"repository-readiness accepts only --runtime-store <path>",
));
}
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 <id>",
)
},
)?,
embedding_model: options.workspace_embedding_model.clone().ok_or_else(|| {
usage_error("repository-readiness requires --workspace-embedding-model <model>")
})?,
vector_dimensions: options.workspace_vector_dimensions.ok_or_else(|| {
usage_error("repository-readiness requires --workspace-vector-dimensions <n>")
})?,
};
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<String>,
budget: Option<u32>,
profile: Option<epiphany_core::EpiphanyMemoryProfile>,
workspace_embedding_provider_id: Option<String>,
workspace_embedding_model: Option<String>,
workspace_vector_dimensions: Option<u32>,
}
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<epiphany_core::EpiphanyMemoryProfile> {
fn usage_error(message: &str) -> anyhow::Error {
anyhow!(
"{message}\nusage: epiphany-memory-semantic <context|health> (--runtime-store <path>|--agent-store <path>|--graph-store <path>) [--swarm-id <id>] --partition <mind|modeling> [--local-verse-store <path> --runtime-id <id> --provider-incarnation <id>] [--text <query>] [--query-id <id>] [--budget <n>] [--profile <profile>]"
"{message}\nusage: epiphany-memory-semantic <context|health|repository-readiness> (--runtime-store <path>|--agent-store <path>|--graph-store <path>) [--swarm-id <id>] --partition <mind|modeling> [--local-verse-store <path> --runtime-id <id> --provider-incarnation <id>] [--text <query>] [--query-id <id>] [--budget <n>] [--profile <profile>] [--workspace-embedding-provider-id <id> --workspace-embedding-model <model> --workspace-vector-dimensions <n>]"
)
}

View file

@ -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;

View file

@ -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<PreparedWorkspaceCoverageProjection> {
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,