diff --git a/Cargo.lock b/Cargo.lock index eb9167c5..0d55a41b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,16 +233,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "assert-json-diff" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "async-broadcast" version = "0.7.2" @@ -543,20 +533,6 @@ dependencies = [ "piper", ] -[[package]] -name = "bm25" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cbd8ffdfb7b4c2ff038726178a780a94f90525ed0ad264c0afaa75dd8c18a64" -dependencies = [ - "cached", - "deunicode", - "fxhash", - "rust-stemmers", - "stop-words", - "unicode-segmentation", -] - [[package]] name = "borsh" version = "1.8.0" @@ -616,39 +592,6 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" -[[package]] -name = "cached" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801927ee168e17809ab8901d9f01f700cd7d8d6a6527997fee44e4b0327a253c" -dependencies = [ - "ahash", - "cached_proc_macro", - "cached_proc_macro_types", - "hashbrown 0.15.5", - "once_cell", - "thiserror 2.0.20", - "web-time", -] - -[[package]] -name = "cached_proc_macro" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9225bdcf4e4a9a4c08bf16607908eb2fbf746828d5e0b5e019726dbf6571f201" -dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "cached_proc_macro_types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" - [[package]] name = "cbc" version = "0.1.2" @@ -1636,38 +1579,14 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", -] - [[package]] name = "darling" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.11.1", - "syn 2.0.119", + "darling_core", + "darling_macro", ] [[package]] @@ -1683,24 +1602,13 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core 0.20.11", - "quote", - "syn 2.0.119", -] - [[package]] name = "darling_macro" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core 0.23.0", + "darling_core", "quote", "syn 2.0.119", ] @@ -1740,24 +1648,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "deadpool" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" -dependencies = [ - "deadpool-runtime", - "lazy_static", - "num_cpus", - "tokio", -] - -[[package]] -name = "deadpool-runtime" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" - [[package]] name = "debugserver-types" version = "0.5.0" @@ -1835,12 +1725,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "deunicode" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" - [[package]] name = "diff" version = "0.1.13" @@ -2102,7 +1986,6 @@ name = "epiphany-core" version = "0.1.0" dependencies = [ "anyhow", - "bm25", "chrono", "ctrlc", "cultcache-rs", @@ -2114,14 +1997,11 @@ dependencies = [ "epiphany-release-construction", "epiphany-state-model", "epiphany-tool-adapter", - "fs2", "ghostlight-persona-projection", "ignore", "libc", - "postgres", "pretty_assertions", "rand_core 0.6.4", - "reqwest 0.12.28", "rmp-serde", "semver", "serde", @@ -2129,12 +2009,8 @@ dependencies = [ "sha1", "sha2 0.10.9", "tempfile", - "tokio", - "tracing", "uuid", "windows-sys 0.59.0", - "wiremock", - "zeroize", ] [[package]] @@ -2205,7 +2081,6 @@ name = "epiphany-release-bundle" version = "0.1.0" dependencies = [ "anyhow", - "bm25", "chrono", "ctrlc", "cultcache-rs", @@ -2450,12 +2325,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -2764,17 +2633,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -2783,7 +2641,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -2990,7 +2848,6 @@ dependencies = [ "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -4056,16 +3913,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "objc2" version = "0.6.4" @@ -5642,7 +5489,7 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e88ad84b8b6237a934534a62b379a5be6388915663c0cc598ceb9b3292bbbfe" dependencies = [ - "darling 0.23.0", + "darling", "proc-macro2", "quote", "serde_json", @@ -5679,16 +5526,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "rust-stemmers" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" -dependencies = [ - "serde", - "serde_derive", -] - [[package]] name = "rustc-hash" version = "2.1.3" @@ -6212,7 +6049,7 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ - "darling 0.23.0", + "darling", "proc-macro2", "quote", "syn 2.0.119", @@ -6504,15 +6341,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stop-words" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645a3d441ccf4bf47f2e4b7681461986681a6eeea9937d4c3bc9febd61d17c71" -dependencies = [ - "serde_json", -] - [[package]] name = "streaming-iterator" version = "0.1.9" @@ -8027,29 +7855,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "wiremock" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" -dependencies = [ - "assert-json-diff", - "base64", - "deadpool", - "futures", - "http", - "http-body-util", - "hyper", - "hyper-util", - "log", - "once_cell", - "regex", - "serde", - "serde_json", - "tokio", - "url", -] - [[package]] name = "wit-bindgen" version = "0.57.1" diff --git a/Cargo.toml b/Cargo.toml index 36b9e6fd..97f29cd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ license-file = "LICENSE" [dependencies] anyhow = "1" -bm25 = "2.3.2" chrono = "0.4.44" ctrlc = { version = "3.5.1", features = ["termination"] } cultcache-rs = { path = "vendor/cultcache-rs" } @@ -80,10 +79,6 @@ tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev [patch."ssh://git@github.com/openai-oss-forks/tungstenite-rs.git"] tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" } -[[bin]] -name = "epiphany-daemon-supervisor" -path = "epiphany-core/src/bin/epiphany-daemon-supervisor.rs" - [[bin]] name = "epiphany-atlas-publisher" path = "epiphany-core/src/bin/epiphany-atlas-publisher.rs" @@ -104,18 +99,6 @@ path = "epiphany-core/src/bin/epiphany-release.rs" name = "epiphany-state" path = "epiphany-core/src/bin/epiphany-state.rs" -[[bin]] -name = "epiphany-memory-semantic-projector" -path = "epiphany-core/src/bin/epiphany-memory-semantic-projector.rs" - -[[bin]] -name = "epiphany-workspace-coverage-projector" -path = "epiphany-core/src/bin/epiphany-workspace-coverage-projector.rs" - -[[bin]] -name = "epiphany-memory-semantic" -path = "epiphany-core/src/bin/epiphany-memory-semantic.rs" - [[bin]] name = "epiphany-repository-body" path = "epiphany-core/src/bin/epiphany-repository-body.rs" diff --git a/epiphany-core/Cargo.toml b/epiphany-core/Cargo.toml index b33acf4f..1920f8cf 100644 --- a/epiphany-core/Cargo.toml +++ b/epiphany-core/Cargo.toml @@ -16,7 +16,6 @@ path = "src/bin/epiphany-prepare-compaction.rs" [dependencies] anyhow = "1" -bm25 = "2.3.2" chrono = "0.4.44" ctrlc = { version = "3.5.1", features = ["termination"] } cultcache-rs = { path = "../vendor/cultcache-rs" } @@ -29,26 +28,19 @@ epiphany-tool-adapter = { path = "../epiphany-tool-adapter" } epiphany-state-model = { path = "../epiphany-state-model" } ghostlight-persona-projection = { git = "https://github.com/GameCult/Ghostlight.git", rev = "22281891cbf9258db80c15a9fd465e6fa251e7dd", package = "ghostlight-persona-projection" } ed25519-dalek = "2" -fs2 = "0.4" ignore = "0.4.23" rand_core = { version = "0.6", features = ["getrandom"] } -zeroize = "1" -postgres = "0.19" -reqwest = { version = "0.12", features = ["blocking", "json"] } rmp-serde = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" semver = { version = "1", features = ["serde"] } sha1 = "0.10.6" sha2 = "0.10" -tracing = "0.1.44" uuid = { version = "1", features = ["serde", "v4", "v5"] } [dev-dependencies] pretty_assertions = "1.4.1" tempfile = "3" -tokio = { version = "1", features = ["rt", "rt-multi-thread"] } -wiremock = "0.6" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading"] } diff --git a/epiphany-core/src/bin/epiphany-daemon-supervisor.rs b/epiphany-core/src/bin/epiphany-daemon-supervisor.rs deleted file mode 100644 index cd2de0fe..00000000 --- a/epiphany-core/src/bin/epiphany-daemon-supervisor.rs +++ /dev/null @@ -1,2155 +0,0 @@ -use anyhow::Context; -use anyhow::Result; -use chrono::DateTime; -use chrono::Duration; -use chrono::Utc; -use cultnet_rs::{ - GameCultProviderHealthIdentity, ServiceIdentitySigner, enroll_service_identity_at, - export_service_identity_trust_anchor, open_service_identity_at, -}; -use ed25519_dalek::SigningKey; -use epiphany_core::EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION; -use epiphany_core::EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION; -use epiphany_core::EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry; -use epiphany_core::EpiphanyCultMeshManagedServicePolicyEntry; -use epiphany_core::EpiphanyCultMeshSwarmBrakeEntry; -use epiphany_core::EpiphanyProcessObservation as ProcessObservation; -use epiphany_core::authenticate_epiphany_cultmesh_semantic_projector_launch; -use epiphany_core::authenticate_resident_provider; -use epiphany_core::idunn_recover_memory_semantic_projection_from_cultmesh; -use epiphany_core::load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service; -use epiphany_core::load_epiphany_cultmesh_managed_service_policies; -use epiphany_core::load_epiphany_cultmesh_managed_service_policy; -use epiphany_core::load_epiphany_cultmesh_managed_service_policy_with_digest; -use epiphany_core::load_epiphany_cultmesh_swarm_brake; -use epiphany_core::load_epiphany_packaged_release; -use epiphany_core::load_latest_epiphany_cultmesh_daemon_heartbeat; -use epiphany_core::observe_native_process as observe_process; -use epiphany_core::runtime_modeling_semantic_projection_input; -use epiphany_core::write_epiphany_cultmesh_daemon_service_lifecycle_receipt; -use epiphany_core::write_epiphany_cultmesh_semantic_projector_service_policy; -use epiphany_core::write_epiphany_cultmesh_workspace_coverage_projector_service_policy; -use epiphany_core::{ - EpiphanyAggregateRuntimeHealthInput, derive_epiphany_aggregate_runtime_health, - publish_idunn_daemon_health_rudp, sign_epiphany_runtime_health, -}; -use epiphany_core::{EpiphanyPackagedReleaseEntry, authenticate_epiphany_packaged_release}; -use epiphany_core::{ - ProcessInstanceIdentity, ProcessInstanceObservation, - WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION, WorkspaceCoverageManagedProcessLaunchEntry, - WorkspaceCoverageProcessBootstrap, WorkspaceCoverageProcessLifecycleObservation, - authenticate_recovery_workspace_coverage_claim_sight, - authenticate_workspace_coverage_managed_process_launch, - authenticate_workspace_coverage_provider_heartbeat, - authenticate_workspace_coverage_replacement_lineage, - authenticate_workspace_coverage_termination_with_envelope_digest, capture_process_instance, - load_latest_workspace_coverage_managed_process_launch, - load_latest_workspace_coverage_provider_heartbeat, - load_workspace_coverage_process_termination_observation, native_boot_identity, - observe_historical_workspace_coverage_managed_process, observe_process_instance, - observe_workspace_coverage_managed_process, open_default_host_identity, - process_identity_from_workspace_coverage_launch, sign_workspace_coverage_launch, - workspace_coverage_host_identity_record_digest, - write_workspace_coverage_managed_process_launch, write_workspace_coverage_process_bootstrap, - write_workspace_coverage_process_termination_observation, - write_workspace_coverage_recovery_directive, -}; -use epiphany_core::{ - authenticate_current_workspace_coverage_advancement_sight, - authenticate_current_workspace_coverage_terminal_sight, -}; -use epiphany_core::{ - epiphany_packaged_release_binary_path, epiphany_packaged_release_witness_sha256, -}; -use rand_core::{OsRng, RngCore}; -use serde_json::json; -use sha2::Digest; -use sha2::Sha256; -use std::env; -use std::fs; -use std::net::SocketAddr; -use std::path::{Path, PathBuf}; -use std::process::Child; -use std::process::Command; -use std::process::Stdio; -use std::thread; -use std::time::Duration as StdDuration; -use uuid::Uuid; -use zeroize::Zeroize; - -const SEMANTIC_PROJECTOR_SERVICE_ID: &str = "epiphany-memory-semantic-projector-service"; -const SEMANTIC_PROJECTOR_EXECUTOR_ID: &str = "epiphany-memory-semantic-projector"; -const WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID: &str = - "epiphany-workspace-coverage-projector-service"; -const WORKSPACE_COVERAGE_PROJECTOR_EXECUTOR_ID: &str = "epiphany-workspace-coverage-projector"; -const AGGREGATE_HEARTBEAT_FRESH_SECONDS: i64 = 180; -const WORKSPACE_PROGRESS_NO_ADVANCE_LEASE_SECONDS: i64 = 300; - -enum ManagedServiceLineage { - Current, - Pending, - Stale(String), -} - -#[cfg(windows)] -use std::os::windows::process::CommandExt; - -fn main() -> Result<()> { - let args = Args::parse()?; - let fatal_log = args.fatal_log.clone(); - let result = dispatch(args); - if let Err(error) = &result - && let Some(path) = fatal_log - { - let _ = append_fatal_log(&path, error); - } - result -} - -fn dispatch(args: Args) -> Result<()> { - match args.command.as_str() { - "managed-service-serve" => managed_service_serve(args), - "provider-health-identity-enroll" => provider_health_identity_enroll(args), - "provider-health-identity-export" => provider_health_identity_export(args), - "semantic-projector-service-policy" => semantic_projector_service_policy(args), - "workspace-coverage-projector-service-policy" => { - workspace_coverage_projector_service_policy(args) - } - "semantic-recover" => semantic_recover(args), - other => anyhow::bail!( - "unknown command {other:?}; use managed-service-serve, provider-health-identity-enroll/export, semantic-projector-service-policy, workspace-coverage-projector-service-policy, or semantic-recover" - ), - } -} - -fn append_fatal_log(path: &Path, error: &anyhow::Error) -> Result<()> { - use std::io::Write; - if let Some(parent) = path.parent() { - fs::create_dir_all(parent)?; - } - let mut file = fs::OpenOptions::new() - .create(true) - .append(true) - .open(path)?; - writeln!(file, "{} {}", Utc::now().to_rfc3339(), error)?; - Ok(()) -} - -fn provider_health_identity_enroll(args: Args) -> Result<()> { - let path = args.idunn_provider_health_identity_store.context( - "provider-health identity enrollment requires --idunn-provider-health-identity-store", - )?; - let signer = enroll_service_identity_at::(&path)?; - println!( - "{}", - serde_json::to_string_pretty(&json!({ - "schemaVersion": "epiphany.provider_health_identity_enrollment.v2", - "identityId": signer.entry().identity_id, - "publicKeyHex": lowercase_hex(&signer.entry().public_key), - "privateStateExposed": false, - }))? - ); - Ok(()) -} - -fn provider_health_identity_export(args: Args) -> Result<()> { - let private = args.idunn_provider_health_identity_store.context( - "provider-health identity export requires --idunn-provider-health-identity-store", - )?; - let public = args.idunn_provider_health_public_anchor.context( - "provider-health identity export requires --idunn-provider-health-public-anchor", - )?; - if private == public { - anyhow::bail!("provider-health private identity and public anchor paths must differ"); - } - let signer = open_service_identity_at::(&private)?; - export_service_identity_trust_anchor(&signer, &public)?; - println!( - "{}", - serde_json::to_string_pretty(&json!({ - "schemaVersion": "epiphany.provider_health_identity_export.v2", - "identityId": signer.entry().identity_id, - "publicKeyHex": lowercase_hex(&signer.entry().public_key), - "publicAnchor": public, - "privateStateExposed": false, - }))? - ); - Ok(()) -} - -fn lowercase_hex(bytes: &[u8]) -> String { - bytes.iter().map(|byte| format!("{byte:02x}")).collect() -} - -fn pinned_packaged_release( - args: &Args, - require_digest: bool, -) -> Result<(EpiphanyPackagedReleaseEntry, String)> { - let release_id = args - .release_id - .as_deref() - .context("managed-service deployment requires --release-id")?; - let witness = load_epiphany_packaged_release(&args.store, &args.runtime_id, release_id)? - .context("pinned packaged release is absent")?; - let digest = match args.release_witness_sha256.as_deref() { - Some(expected) => expected.to_string(), - None if require_digest => { - anyhow::bail!("managed-service runtime requires --release-witness-sha256") - } - None => epiphany_packaged_release_witness_sha256(&witness)?, - }; - let authenticated = - authenticate_epiphany_packaged_release(&args.store, &args.runtime_id, release_id, &digest)?; - Ok((authenticated, digest)) -} - -fn required<'a>(value: &'a Option, flag: &str) -> Result<&'a str> { - value.as_deref().with_context(|| format!("missing {flag}")) -} - -fn semantic_recover(args: Args) -> Result<()> { - let store = args - .runtime_store - .as_ref() - .context("semantic-recover requires --runtime-store")?; - let input = runtime_modeling_semantic_projection_input(store)?; - let (authorization, claim) = idunn_recover_memory_semantic_projection_from_cultmesh( - &args.store, - args.runtime_id.clone(), - store, - &input, - required(&args.expected_claim_id, "--expected-claim-id")?, - SEMANTIC_PROJECTOR_EXECUTOR_ID, - required(&args.receipt_id, "--receipt-id")?, - required(&args.provider_heartbeat_id, "--provider-heartbeat-id")?, - &Utc::now().to_rfc3339(), - )?; - println!( - "{}", - serde_json::to_string_pretty(&json!({ - "authorizationId": authorization.authorization_id, - "epoch": claim.epoch, - "executorId": claim.executor_id, - "privateStateExposed": false - }))? - ); - Ok(()) -} - -fn managed_service_serve(args: Args) -> Result<()> { - let (release, _) = pinned_packaged_release(&args, true)?; - let expected_supervisor = fs::canonicalize(epiphany_packaged_release_binary_path( - &release, - "supervisor", - )?)?; - if fs::canonicalize(env::current_exe()?)? != expected_supervisor { - anyhow::bail!("managed-service reconciler executable is not the pinned release supervisor"); - } - let health_signer = args - .idunn_provider_health_identity_store - .as_deref() - .map(open_service_identity_at::) - .transpose()?; - let health_publisher_incarnation = Uuid::new_v4().to_string(); - let mut iteration = 0_u64; - loop { - let (release, release_witness_sha256) = pinned_packaged_release(&args, true)?; - iteration = iteration - .checked_add(1) - .context("aggregate runtime health sequence exhausted")?; - let policies = - load_epiphany_cultmesh_managed_service_policies(&args.store, args.runtime_id.clone())?; - let brake = load_epiphany_cultmesh_swarm_brake(&args.store, args.runtime_id.clone())?; - let lifecycle_braked = swarm_brake_blocks_service_lifecycle_entry(brake.as_ref()); - if !lifecycle_braked { - for policy in &policies { - let mut service_args = args.clone(); - service_args.service_id = policy.service_id.clone(); - managed_service_reconcile(service_args)?; - } - } - publish_managed_service_iteration_health( - &args, - &release, - &release_witness_sha256, - &policies, - lifecycle_braked, - &health_publisher_incarnation, - iteration, - health_signer.as_ref(), - ); - if args.max_iterations != 0 && iteration >= args.max_iterations { - break; - } - std::thread::sleep(std::time::Duration::from_secs( - args.loop_interval_seconds.max(0) as u64, - )); - } - Ok(()) -} - -const REQUIRED_MANAGED_HEALTH_SERVICES: [&str; 2] = [ - SEMANTIC_PROJECTOR_SERVICE_ID, - WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID, -]; - -fn required_managed_health_services(lifecycle_braked: bool) -> &'static [&'static str] { - if lifecycle_braked { - &[] - } else { - &REQUIRED_MANAGED_HEALTH_SERVICES - } -} - -fn publish_managed_service_iteration_health( - args: &Args, - release: &EpiphanyPackagedReleaseEntry, - authenticated_release_witness_sha256: &str, - policies: &[EpiphanyCultMeshManagedServicePolicyEntry], - lifecycle_braked: bool, - publisher_incarnation_id: &str, - publisher_sequence: u64, - health_signer: Option<&ServiceIdentitySigner>, -) { - let (Some(endpoint), Some(daemon_id), Some(health_contract), Some(health_signer)) = ( - args.idunn_rudp_health, - args.idunn_daemon.as_deref(), - args.idunn_health_contract.as_deref(), - health_signer, - ) else { - return; - }; - let required = required_managed_health_services(lifecycle_braked); - let mut expected = required.len(); - let mut terminal_current = 0_usize; - let mut warming = 0_usize; - let mut contradictions = Vec::new(); - if let Some(resident_store) = args.resident_self_store.as_deref() { - expected += 1; - let provider = authenticate_resident_provider( - release, - authenticated_release_witness_sha256, - resident_store, - args.resident_provider_stale_seconds.saturating_mul(1000), - ); - terminal_current += provider.terminal_current; - warming += provider.warming; - contradictions.extend(provider.contradictions); - } - for &service_id in required { - let Some(policy) = policies - .iter() - .find(|policy| policy.service_id == service_id) - else { - continue; - }; - if !policy.enabled { - continue; - } - match managed_service_lineage(args, release, policy) { - Ok(ManagedServiceLineage::Current) - if policy.service_id == WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID => - { - let runtime_store = match args.runtime_store.as_deref() { - Some(store) => store, - None => { - contradictions - .push("workspace health lacks the bound runtime store".to_string()); - continue; - } - }; - let host = match open_default_host_identity() { - Ok(host) => host, - Err(error) => { - contradictions.push(format!( - "workspace health cannot authenticate host: {error:#}" - )); - continue; - } - }; - match authenticate_current_workspace_coverage_terminal_sight( - runtime_store, - &args.store, - &args.runtime_id, - host.entry(), - ) { - Ok(Some(_authority)) => { - terminal_current += 1; - } - Ok(None) => { - let launch = match load_latest_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - ) { - Ok(Some(launch)) => launch, - Ok(None) => continue, - Err(error) => { - contradictions.push(format!( - "workspace health cannot load launch: {error:#}" - )); - continue; - } - }; - match authenticate_current_workspace_coverage_advancement_sight( - runtime_store, - &args.store, - &args.runtime_id, - &launch.launch_id, - host.entry(), - ) { - Ok(Some(authority)) => { - let advanced = - DateTime::parse_from_rfc3339(&authority.last_advanced_at_utc) - .map(|time| time.with_timezone(&Utc)); - match advanced { - Ok(advanced) if Utc::now().signed_duration_since(advanced) >= Duration::zero() - && Utc::now().signed_duration_since(advanced) <= Duration::seconds(WORKSPACE_PROGRESS_NO_ADVANCE_LEASE_SECONDS) => { - warming += 1; - } - Ok(_) => contradictions.push("workspace advancement sight exceeded the supervisor no-advance lease".into()), - Err(error) => contradictions.push(format!("workspace advancement sight time is invalid: {error:#}")), - } - } - Ok(None) => {} - Err(error) => contradictions.push(format!( - "workspace advancement authority is invalid: {error:#}" - )), - } - } - Err(error) => contradictions.push(format!( - "workspace terminal authority is invalid: {error:#}" - )), - } - } - Ok(ManagedServiceLineage::Current) => terminal_current += 1, - Ok(ManagedServiceLineage::Pending) => {} - Ok(ManagedServiceLineage::Stale(reason)) => { - contradictions.push(format!("{}: {reason}", policy.service_id)) - } - Err(error) => contradictions.push(format!("{}: {error:#}", policy.service_id)), - } - } - let health = derive_epiphany_aggregate_runtime_health(EpiphanyAggregateRuntimeHealthInput { - daemon_id: daemon_id.to_string(), - health_contract: health_contract.to_string(), - observed_at: Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true), - release_authenticated: true, - expected_service_count: expected, - terminal_current_service_count: terminal_current, - warming_service_count: warming, - contradictions, - }); - match health.and_then(|health| { - let witness_sha256 = epiphany_packaged_release_witness_sha256(release)?; - if witness_sha256 != authenticated_release_witness_sha256 { - anyhow::bail!("aggregate health release witness changed after authentication"); - } - let signed = sign_epiphany_runtime_health( - health, - &args.runtime_id, - &release.release_id, - &witness_sha256, - &release.source_commit_sha, - args.idunn_deployment_request_id - .as_deref() - .context("aggregate health requires --idunn-deployment-request-id")?, - publisher_incarnation_id, - publisher_sequence, - health_signer, - )?; - publish_idunn_daemon_health_rudp(endpoint, &args.runtime_id, &signed) - }) { - Ok(()) => {} - Err(error) => eprintln!("Epiphany could not publish aggregate Idunn health: {error:#}"), - } -} - -fn managed_service_lineage( - args: &Args, - release: &EpiphanyPackagedReleaseEntry, - policy: &EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result { - let (_, policy_digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( - &args.store, - args.runtime_id.clone(), - &policy.service_id, - )? - .with_context(|| { - format!( - "managed service policy disappeared for {}", - policy.service_id - ) - })?; - if policy.service_id == WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID { - let Some(launch) = load_latest_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - )? - else { - return Ok(ManagedServiceLineage::Pending); - }; - let host = open_default_host_identity()?; - let launch = authenticate_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - &launch.launch_id, - host.entry(), - )?; - if launch.policy_envelope_digest != policy_digest { - return Ok(ManagedServiceLineage::Stale( - "workspace child launch disagrees with current policy digest".into(), - )); - } - let expected = fs::canonicalize(epiphany_packaged_release_binary_path( - release, - "workspace-coverage-projector", - )?)?; - if fs::canonicalize(&launch.process_executable_path)? != expected { - return Ok(ManagedServiceLineage::Stale( - "workspace child executable is outside current packaged release".into(), - )); - } - let Some(heartbeat) = load_latest_workspace_coverage_provider_heartbeat( - &args.store, - args.runtime_id.clone(), - &launch.launch_id, - )? - else { - return Ok(ManagedServiceLineage::Pending); - }; - let heartbeat = authenticate_workspace_coverage_provider_heartbeat( - &args.store, - args.runtime_id.clone(), - &heartbeat.heartbeat_id, - host.entry(), - )?; - if heartbeat.status != "ready" || !timestamp_is_fresh(&heartbeat.observed_at_utc)? { - return Ok(ManagedServiceLineage::Pending); - } - let identity = ProcessInstanceIdentity { - process_id: launch.process_id, - creation_token: launch.process_creation_token, - created_at_rfc3339: launch.process_created_at_rfc3339, - executable_path: PathBuf::from(launch.process_executable_path), - }; - return Ok( - if observe_process_instance(&identity) == ProcessInstanceObservation::ExactAlive { - ManagedServiceLineage::Current - } else { - ManagedServiceLineage::Pending - }, - ); - } - let Some(receipt) = - load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( - &args.store, - args.runtime_id.clone(), - &policy.service_id, - )? - else { - return Ok(ManagedServiceLineage::Pending); - }; - if receipt.managed_policy_id != policy.policy_id - || receipt.managed_policy_digest != policy_digest - || receipt.command != policy.command - || receipt.args != policy.args - || receipt.cwd != policy.cwd - { - lifecycle_process_identity(&receipt)?; - return Ok(ManagedServiceLineage::Stale( - "alive child lineage disagrees with current managed policy".into(), - )); - } - if policy.service_id == SEMANTIC_PROJECTOR_SERVICE_ID { - authenticate_epiphany_cultmesh_semantic_projector_launch( - &args.store, - args.runtime_id.clone(), - &receipt.receipt_id, - )?; - let expected = fs::canonicalize(epiphany_packaged_release_binary_path( - release, - "semantic-projector", - )?)?; - if fs::canonicalize(&receipt.command)? != expected { - lifecycle_process_identity(&receipt)?; - return Ok(ManagedServiceLineage::Stale( - "semantic child executable is outside current packaged release".into(), - )); - } - let heartbeat = load_latest_epiphany_cultmesh_daemon_heartbeat( - &args.store, - args.runtime_id.clone(), - &receipt.provider_daemon_id, - )?; - let launch_completed = receipt - .completed_at_utc - .as_deref() - .context("semantic launch receipt has no spawn completion time")?; - if !semantic_heartbeat_is_ready( - heartbeat.as_ref(), - &receipt.receipt_id, - launch_completed, - Utc::now(), - )? { - return Ok(ManagedServiceLineage::Pending); - } - } - let identity = lifecycle_process_identity(&receipt)?; - Ok( - if observe_process_instance(&identity) == ProcessInstanceObservation::ExactAlive { - ManagedServiceLineage::Current - } else { - ManagedServiceLineage::Pending - }, - ) -} - -fn lifecycle_process_identity( - receipt: &EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, -) -> Result { - process_identity_from_parts( - receipt.process_id, - receipt.process_creation_token, - receipt.process_created_at_rfc3339.clone(), - &receipt.process_executable_path, - ) -} - -fn process_identity_from_parts( - process_id: Option, - creation_token: u64, - created_at_rfc3339: Option, - executable_path: &str, -) -> Result { - if creation_token == 0 || executable_path.trim().is_empty() { - anyhow::bail!("launch receipt has no authenticated process-instance identity"); - } - Ok(ProcessInstanceIdentity { - process_id: process_id.context("launch receipt has no process id")?, - creation_token, - created_at_rfc3339, - executable_path: PathBuf::from(executable_path), - }) -} - -fn replacement_process_identity( - lineage: &ManagedServiceLineage, - receipt: &EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, -) -> Result> { - replacement_identity_from_parts( - lineage, - receipt.process_id, - receipt.process_creation_token, - receipt.process_created_at_rfc3339.clone(), - &receipt.process_executable_path, - ) -} - -fn replacement_identity_from_parts( - lineage: &ManagedServiceLineage, - process_id: Option, - creation_token: u64, - created_at_rfc3339: Option, - executable_path: &str, -) -> Result> { - match lineage { - ManagedServiceLineage::Stale(_) => process_identity_from_parts( - process_id, - creation_token, - created_at_rfc3339, - executable_path, - ) - .map(Some), - ManagedServiceLineage::Current | ManagedServiceLineage::Pending => Ok(None), - } -} - -fn timestamp_is_fresh(value: &str) -> Result { - timestamp_is_fresh_at(value, Utc::now()) -} - -fn semantic_heartbeat_is_ready( - heartbeat: Option<&epiphany_core::EpiphanyCultMeshDaemonHeartbeatEventEntry>, - lifecycle_receipt_id: &str, - launch_completed_at: &str, - now: DateTime, -) -> Result { - let Some(heartbeat) = heartbeat else { - return Ok(false); - }; - Ok(heartbeat.status == "ready" - && heartbeat.startup_lifecycle_receipt_id == lifecycle_receipt_id - && DateTime::parse_from_rfc3339(&heartbeat.heartbeat_at)? - > DateTime::parse_from_rfc3339(launch_completed_at)? - && timestamp_is_fresh_at(&heartbeat.heartbeat_at, now)?) -} - -fn timestamp_is_fresh_at(value: &str, now: DateTime) -> Result { - let observed = DateTime::parse_from_rfc3339(value)?.with_timezone(&Utc); - let age = now.signed_duration_since(observed); - Ok(age >= Duration::zero() && age <= Duration::seconds(AGGREGATE_HEARTBEAT_FRESH_SECONDS)) -} - -#[derive(Clone)] -struct CoverageReplacementEvidence { - old_launch_id: String, - termination_id: String, - termination_envelope_digest: String, -} - -fn spawn_managed_service( - args: &Args, - command_path: &Path, - environment: &[(&str, String)], - piped_stdin: bool, -) -> Result<(Child, Vec, DateTime)> { - let brake = load_epiphany_cultmesh_swarm_brake(&args.store, args.runtime_id.clone())?; - assert_swarm_brake_allows_service_lifecycle_entry(brake.as_ref())?; - let started_at = Utc::now(); - let service_args = args.service_args.clone(); - let mut command = Command::new(command_path); - command.args(&service_args); - for (key, value) in environment { - command.env(key, value); - } - if piped_stdin { - command.stdin(Stdio::piped()); - } else { - command.stdin(Stdio::null()); - } - if let Some(stdout_path) = &args.stdout_artifact { - if let Some(parent) = stdout_path.parent() { - fs::create_dir_all(parent)?; - } - command.stdout(Stdio::from(fs::File::create(stdout_path)?)); - } else { - command.stdout(Stdio::null()); - } - if let Some(stderr_path) = &args.stderr_artifact { - if let Some(parent) = stderr_path.parent() { - fs::create_dir_all(parent)?; - } - command.stderr(Stdio::from(fs::File::create(stderr_path)?)); - } else { - command.stderr(Stdio::null()); - } - if let Some(cwd) = &args.cwd { - command.current_dir(cwd); - } - #[cfg(windows)] - { - command.creation_flags(0x08000000); - } - let child = command - .spawn() - .with_context(|| format!("failed to launch service {}", command_path.display()))?; - Ok((child, service_args, started_at)) -} - -fn launch_semantic_projector(args: Args) -> Result<()> { - let (policy, policy_digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( - &args.store, - args.runtime_id.clone(), - SEMANTIC_PROJECTOR_SERVICE_ID, - )? - .context("semantic projector managed policy is absent")?; - let command_path = service_command_path(&args)?; - if command_path != PathBuf::from(&policy.command) - || args.service_args != policy.args - || args.cwd.as_ref().map(|path| path.display().to_string()) != policy.cwd - { - anyhow::bail!("semantic projector launch must use the exact current managed policy"); - } - let receipt_id = Uuid::new_v4().to_string(); - let executable_sha256 = local_file_sha256(&command_path.display().to_string()) - .map(|digest| format!("sha256-{digest}")) - .context("semantic projector executable cannot be fingerprinted")?; - let environment = [("EPIPHANY_STARTUP_LIFECYCLE_RECEIPT_ID", receipt_id.clone())]; - let (mut child, service_args, started_at) = - spawn_managed_service(&args, &command_path, &environment, false)?; - let persist_result = (|| { - let identity = capture_process_instance(child.id()) - .context("failed to capture exact semantic projector process identity")?; - if identity.executable_path != command_path.canonicalize()? { - anyhow::bail!("spawned semantic projector executable disagrees with policy command"); - } - let mut receipt = service_lifecycle_receipt( - &args, - "launch", - "launched", - command_path.display().to_string(), - service_args, - Some(child.id()), - None, - started_at, - Some(Utc::now()), - args.stdout_artifact - .as_ref() - .map(|path| path.display().to_string()), - ); - receipt.receipt_id = receipt_id.clone(); - receipt.managed_policy_id = policy.policy_id; - receipt.managed_policy_digest = policy_digest; - receipt.provider_daemon_id = SEMANTIC_PROJECTOR_EXECUTOR_ID.to_string(); - receipt.startup_correlation_id = receipt_id; - receipt.executable_sha256 = executable_sha256; - receipt.process_creation_token = identity.creation_token; - receipt.process_created_at_rfc3339 = identity.created_at_rfc3339; - receipt.process_executable_path = identity.executable_path.display().to_string(); - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &args.store, - args.runtime_id.clone(), - receipt, - ) - })(); - match persist_result { - Ok(_) => Ok(()), - Err(error) => { - let _ = child.kill(); - let _ = child.wait(); - Err(error).context("failed to establish authenticated semantic launch") - } - } -} - -fn launch_workspace_coverage_projector( - args: Args, - replacement: Option, -) -> Result { - let (policy, policy_digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( - &args.store, - args.runtime_id.clone(), - WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID, - )? - .context("workspace coverage managed policy is absent")?; - let command_path = service_command_path(&args)?; - if command_path != PathBuf::from(&policy.command) - || args.service_args != policy.args - || args.cwd.as_ref().map(|path| path.display().to_string()) != policy.cwd - { - anyhow::bail!("workspace coverage launch must use the exact current managed policy"); - } - let host = open_default_host_identity() - .context("workspace coverage launch requires an enrolled host identity")?; - let boot = native_boot_identity() - .context("workspace coverage launch requires a proven native boot identity")?; - let launch_id = Uuid::new_v4(); - let incarnation_id = Uuid::new_v4(); - let mut seed = [0_u8; 32]; - OsRng.fill_bytes(&mut seed); - let provider_key = SigningKey::from_bytes(&seed); - let environment = [( - "EPIPHANY_WORKSPACE_COVERAGE_LAUNCH_ID", - launch_id.to_string(), - )]; - let (mut child, _, started_at) = - spawn_managed_service(&args, &command_path, &environment, true)?; - let persist_result = (|| -> Result { - let process = capture_process_instance(child.id()) - .context("failed to capture exact workspace coverage process identity")?; - let canonical_executable = command_path - .canonicalize() - .context("failed to canonicalize workspace coverage executable")?; - if process.executable_path != canonical_executable { - anyhow::bail!( - "spawned workspace coverage process executable disagrees with policy command" - ); - } - let executable_sha256 = local_file_sha256(&canonical_executable.display().to_string()) - .map(|digest| format!("sha256-{digest}")) - .context("workspace coverage executable cannot be fingerprinted")?; - let mut bootstrap = WorkspaceCoverageProcessBootstrap { - launch_id, - provider_signing_seed: seed, - }; - let mut stdin = child - .stdin - .take() - .context("workspace coverage child stdin is unavailable")?; - write_workspace_coverage_process_bootstrap(&mut stdin, &bootstrap)?; - drop(stdin); - bootstrap.provider_signing_seed.zeroize(); - seed.zeroize(); - let mut launch = WorkspaceCoverageManagedProcessLaunchEntry { - schema_version: WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION.to_string(), - launch_id: launch_id.to_string(), - service_id: WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID.to_string(), - provider_daemon_id: WORKSPACE_COVERAGE_PROJECTOR_EXECUTOR_ID.to_string(), - runtime_id: args.runtime_id.clone(), - policy_id: policy.policy_id, - policy_envelope_digest: policy_digest, - command: policy.command, - args: policy.args, - cwd: policy.cwd, - launched_at_utc: started_at.to_rfc3339(), - host_identity_id: host.entry().identity_id.clone(), - host_public_key: host.entry().public_key.clone(), - host_assurance: host.entry().assurance.clone(), - host_identity_record_digest: workspace_coverage_host_identity_record_digest( - host.entry(), - )?, - boot_identity: boot, - process_id: process.process_id, - process_creation_token: process.creation_token, - process_created_at_rfc3339: process.created_at_rfc3339, - process_executable_path: process.executable_path.display().to_string(), - executable_sha256, - provider_incarnation_id: incarnation_id.to_string(), - provider_public_key: provider_key.verifying_key().to_bytes().to_vec(), - host_signature: Vec::new(), - supervisor_id: "epiphany-daemon-supervisor".to_string(), - identity_captured_at_utc: Utc::now().to_rfc3339(), - signature_algorithm: "ed25519".to_string(), - replaces_launch_id: replacement - .as_ref() - .map(|evidence| evidence.old_launch_id.clone()), - replaces_termination_id: replacement - .as_ref() - .map(|evidence| evidence.termination_id.clone()), - replaces_termination_envelope_digest: replacement - .as_ref() - .map(|evidence| evidence.termination_envelope_digest.clone()), - }; - sign_workspace_coverage_launch(&mut launch, &host)?; - write_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - launch, - host.entry(), - ) - })(); - seed.zeroize(); - let written = match persist_result { - Ok(written) => written, - Err(error) => { - let _ = child.kill(); - let _ = child.wait(); - return Err(error) - .context("failed to establish authenticated workspace coverage launch"); - } - }; - Ok(written) -} - -fn build_managed_service_policy(args: &Args) -> Result { - let command = service_command_path(&args)?; - let stdout_artifact = args.stdout_artifact.clone().unwrap_or_else(|| { - PathBuf::from(format!( - ".epiphany-run/services/{}.stdout.log", - args.service_id - )) - }); - let stderr_artifact = args.stderr_artifact.clone().unwrap_or_else(|| { - PathBuf::from(format!( - ".epiphany-run/services/{}.stderr.log", - args.service_id - )) - }); - Ok(EpiphanyCultMeshManagedServicePolicyEntry { - schema_version: EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION.to_string(), - policy_id: format!("managed-service-policy-{}", sanitize_id(&args.service_id)), - service_id: args.service_id.clone(), - command: command.display().to_string(), - args: args.service_args.clone(), - cwd: args.cwd.as_ref().map(|path| path.display().to_string()), - enabled: !args.disabled, - cooldown_seconds: args.cooldown_seconds, - stdout_artifact: stdout_artifact.display().to_string(), - stderr_artifact: stderr_artifact.display().to_string(), - private_state_exposed: false, - }) -} - -fn report_managed_service_policy( - written: &EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result<()> { - println!( - "{}", - serde_json::to_string_pretty(&json!({ - "schemaVersion": written.schema_version, - "status": "written", - "policyId": written.policy_id, - "serviceId": written.service_id, - "enabled": written.enabled, - "command": written.command, - "args": written.args, - "stdoutArtifact": written.stdout_artifact, - "stderrArtifact": written.stderr_artifact, - "privateStateExposed": written.private_state_exposed, - }))? - ); - Ok(()) -} - -fn bind_managed_policy(args: &mut Args, policy: &EpiphanyCultMeshManagedServicePolicyEntry) { - args.service_command = Some(PathBuf::from(&policy.command)); - args.service_args = policy.args.clone(); - args.cwd = policy.cwd.as_ref().map(PathBuf::from); - args.stdout_artifact = Some(PathBuf::from(&policy.stdout_artifact)); - args.stderr_artifact = Some(PathBuf::from(&policy.stderr_artifact)); -} - -fn semantic_projector_service_policy(mut args: Args) -> Result<()> { - let runtime_store = args - .runtime_store - .as_ref() - .context("semantic-projector-service-policy requires --runtime-store")?; - let qdrant_url = args - .qdrant_url - .as_deref() - .context("semantic-projector-service-policy requires --qdrant-url")?; - let ollama_base_url = args - .ollama_base_url - .as_deref() - .context("semantic-projector-service-policy requires --ollama-base-url")?; - args.service_id = SEMANTIC_PROJECTOR_SERVICE_ID.to_string(); - args.service_command = Some(packaged_role_command_path(&args, "semantic-projector")?); - args.service_args = semantic_projector_service_args( - runtime_store, - &args.store, - &args.runtime_id, - args.loop_interval_seconds, - qdrant_url, - ollama_base_url, - &args.ollama_model, - ); - if args.max_iterations != 0 { - anyhow::bail!("semantic projector managed service must not have a finite iteration limit"); - } - let policy = build_managed_service_policy(&args)?; - let written = write_epiphany_cultmesh_semantic_projector_service_policy( - &args.store, - args.runtime_id, - policy, - )?; - report_managed_service_policy(&written) -} - -fn workspace_coverage_projector_service_policy(mut args: Args) -> Result<()> { - let runtime_store = args - .runtime_store - .as_ref() - .context("workspace-coverage-projector-service-policy requires --runtime-store")?; - let qdrant_url = args - .qdrant_url - .as_deref() - .context("workspace-coverage-projector-service-policy requires --qdrant-url")?; - let ollama_base_url = args - .ollama_base_url - .as_deref() - .context("workspace-coverage-projector-service-policy requires --ollama-base-url")?; - args.service_id = WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID.to_string(); - args.service_command = Some(packaged_role_command_path( - &args, - "workspace-coverage-projector", - )?); - args.service_args = workspace_coverage_projector_service_args( - runtime_store, - &args.store, - &args.runtime_id, - args.loop_interval_seconds, - qdrant_url, - ollama_base_url, - &args.ollama_model, - ); - if args.max_iterations != 0 { - anyhow::bail!( - "workspace coverage projector managed service must not have a finite iteration limit" - ); - } - let policy = build_managed_service_policy(&args)?; - let written = write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &args.store, - args.runtime_id, - policy, - )?; - report_managed_service_policy(&written) -} - -fn packaged_role_command_path(args: &Args, role: &str) -> Result { - let (release, _) = pinned_packaged_release(args, true)?; - epiphany_packaged_release_binary_path(&release, role) -} - -fn workspace_coverage_projector_service_args( - runtime_store: &Path, - local_verse_store: &Path, - runtime_id: &str, - interval_seconds: i64, - qdrant_url: &str, - ollama_base_url: &str, - ollama_model: &str, -) -> Vec { - vec![ - "serve".to_string(), - "--runtime-store".to_string(), - runtime_store.display().to_string(), - "--local-verse-store".to_string(), - local_verse_store.display().to_string(), - "--runtime-id".to_string(), - runtime_id.to_string(), - "--interval-seconds".to_string(), - interval_seconds.to_string(), - "--heartbeat-interval-seconds".to_string(), - "10".to_string(), - "--qdrant-url".to_string(), - qdrant_url.to_string(), - "--ollama-base-url".to_string(), - ollama_base_url.to_string(), - "--ollama-model".to_string(), - ollama_model.to_string(), - ] -} - -fn semantic_projector_service_args( - runtime_store: &Path, - local_verse_store: &Path, - runtime_id: &str, - interval_seconds: i64, - qdrant_url: &str, - ollama_base_url: &str, - ollama_model: &str, -) -> Vec { - vec![ - "serve".to_string(), - "--runtime-store".to_string(), - runtime_store.display().to_string(), - "--local-verse-store".to_string(), - local_verse_store.display().to_string(), - "--runtime-id".to_string(), - runtime_id.to_string(), - "--interval-seconds".to_string(), - interval_seconds.to_string(), - "--qdrant-url".to_string(), - qdrant_url.to_string(), - "--ollama-base-url".to_string(), - ollama_base_url.to_string(), - "--ollama-model".to_string(), - ollama_model.to_string(), - ] -} - -fn managed_service_reconcile(mut args: Args) -> Result<()> { - let brake = load_epiphany_cultmesh_swarm_brake(&args.store, args.runtime_id.clone())?; - assert_swarm_brake_allows_service_lifecycle_entry(brake.as_ref())?; - let pinned_release = pinned_packaged_release(&args, true)?.0; - let policy = load_epiphany_cultmesh_managed_service_policy( - &args.store, - args.runtime_id.clone(), - &args.service_id, - )? - .with_context(|| format!("managed service policy missing for {}", args.service_id))?; - let expected_role = match policy.service_id.as_str() { - SEMANTIC_PROJECTOR_SERVICE_ID => "semantic-projector", - WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID => "workspace-coverage-projector", - other => anyhow::bail!("unsupported managed service policy {other}"), - }; - if fs::canonicalize(&policy.command)? - != fs::canonicalize(epiphany_packaged_release_binary_path( - &pinned_release, - expected_role, - )?)? - { - anyhow::bail!( - "reserved managed-service policy command is outside pinned release role {expected_role}" - ); - } - if policy.service_id == WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID { - return reconcile_workspace_coverage_projector(args, policy); - } - let current = load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( - &args.store, - args.runtime_id.clone(), - &args.service_id, - )?; - let mut observation = current - .as_ref() - .and_then(|receipt| receipt.process_id) - .map(observe_process) - .transpose()? - .unwrap_or(ProcessObservation::Missing); - if observation == ProcessObservation::Alive { - let lineage = - managed_service_lineage(&args, &pinned_release, &policy).with_context(|| { - format!("failed to authenticate {} child lineage", policy.service_id) - })?; - if let Some(identity) = replacement_process_identity( - &lineage, - current - .as_ref() - .context("alive managed service has no lifecycle receipt")?, - )? { - terminate_native_process_instance(&identity)?; - observation = ProcessObservation::Missing; - } - } - if !policy.enabled { - return Ok(()); - } - if observation == ProcessObservation::Alive { - return Ok(()); - } - if !args.force && policy.cooldown_seconds > 0 { - if let Some(started) = current - .as_ref() - .and_then(|receipt| DateTime::parse_from_rfc3339(&receipt.started_at_utc).ok()) - { - let elapsed = Utc::now().signed_duration_since(started.with_timezone(&Utc)); - if elapsed < Duration::seconds(policy.cooldown_seconds) { - return Ok(()); - } - } - } - bind_managed_policy(&mut args, &policy); - launch_semantic_projector(args) -} - -fn terminate_native_process_instance(identity: &ProcessInstanceIdentity) -> Result<()> { - if observe_process_instance(identity) != ProcessInstanceObservation::ExactAlive { - anyhow::bail!("stale managed-service process identity drifted before termination"); - } - let process_id = identity.process_id; - #[cfg(windows)] - let status = Command::new("taskkill") - .args(["/PID", &process_id.to_string(), "/T", "/F"]) - .status()?; - #[cfg(not(windows))] - let status = Command::new("kill") - .args(["-TERM", &process_id.to_string()]) - .status()?; - if !status.success() { - anyhow::bail!("failed to terminate stale managed-service process {process_id}"); - } - Ok(()) -} - -fn reconcile_workspace_coverage_projector( - mut args: Args, - policy: EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result<()> { - if !policy.enabled { - return Ok(()); - } - let runtime_store = args.runtime_store.clone().context( - "workspace coverage reconciliation requires --runtime-store for Body/route sight", - )?; - let host = open_default_host_identity() - .context("workspace coverage reconciliation requires an enrolled host identity")?; - let latest = load_latest_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - )?; - let Some(latest) = latest else { - bind_managed_policy(&mut args, &policy); - launch_workspace_coverage_projector(args, None)?; - return Ok(()); - }; - let current_policy_matches_latest = latest.policy_id == policy.policy_id - && latest.command == policy.command - && latest.args == policy.args - && latest.cwd == policy.cwd - && load_epiphany_cultmesh_managed_service_policy_with_digest( - &args.store, - args.runtime_id.clone(), - &policy.service_id, - )? - .is_some_and(|(_, digest)| digest == latest.policy_envelope_digest); - if !current_policy_matches_latest { - let observation = observe_historical_workspace_coverage_managed_process( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - if observation == WorkspaceCoverageProcessLifecycleObservation::ExactAlive { - terminate_native_process_instance(&process_identity_from_workspace_coverage_launch( - &latest, - ))?; - return Ok(()); - } - if matches!( - observation, - WorkspaceCoverageProcessLifecycleObservation::Inaccessible - | WorkspaceCoverageProcessLifecycleObservation::Indeterminate { .. } - ) { - return Ok(()); - } - if load_workspace_coverage_process_termination_observation( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - )? - .is_none() - { - write_workspace_coverage_process_termination_observation( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - &host, - )?; - } - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - bind_managed_policy(&mut args, &policy); - launch_workspace_coverage_projector( - args, - Some(CoverageReplacementEvidence { - old_launch_id: latest.launch_id, - termination_id: termination.termination_id, - termination_envelope_digest: termination_digest, - }), - )?; - return Ok(()); - } - let terminal_sight = authenticate_current_workspace_coverage_terminal_sight( - &runtime_store, - &args.store, - &args.runtime_id, - host.entry(), - )?; - if let Some(terminal) = terminal_sight { - if terminal.launch_id != latest.launch_id { - authenticate_workspace_coverage_replacement_lineage( - &args.store, - &args.runtime_id, - &terminal.launch_id, - &latest.launch_id, - host.entry(), - )?; - } - let observation = observe_workspace_coverage_managed_process( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - match observation { - WorkspaceCoverageProcessLifecycleObservation::ExactAlive => return Ok(()), - WorkspaceCoverageProcessLifecycleObservation::Inaccessible - | WorkspaceCoverageProcessLifecycleObservation::Indeterminate { .. } => return Ok(()), - WorkspaceCoverageProcessLifecycleObservation::BootSuperseded { .. } - | WorkspaceCoverageProcessLifecycleObservation::ExactExited { .. } - | WorkspaceCoverageProcessLifecycleObservation::Missing - | WorkspaceCoverageProcessLifecycleObservation::Replaced { .. } => {} - } - if load_workspace_coverage_process_termination_observation( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - )? - .is_none() - { - write_workspace_coverage_process_termination_observation( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - &host, - )?; - } - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - bind_managed_policy(&mut args, &policy); - launch_workspace_coverage_projector( - args, - Some(CoverageReplacementEvidence { - old_launch_id: latest.launch_id, - termination_id: termination.termination_id, - termination_envelope_digest: termination_digest, - }), - )?; - return Ok(()); - } - let target = authenticate_recovery_workspace_coverage_claim_sight( - &args.store, - &runtime_store, - &args.runtime_id, - host.entry(), - )?; - if target - .as_ref() - .is_some_and(|claim| claim.launch_id != latest.launch_id) - { - let old_target = target - .clone() - .context("workspace coverage mismatch lost its authenticated claim target")?; - let replacement = authenticate_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - authenticate_workspace_coverage_replacement_lineage( - &args.store, - &args.runtime_id, - &old_target.launch_id, - &latest.launch_id, - host.entry(), - )?; - return match observe_workspace_coverage_managed_process( - &args.store, - args.runtime_id.clone(), - &replacement.launch_id, - host.entry(), - )? { - WorkspaceCoverageProcessLifecycleObservation::ExactAlive => { - finish_workspace_coverage_recovery( - &args, - &runtime_store, - host.entry(), - &host, - old_target, - replacement, - ) - } - _ => Ok(()), - }; - } - let observation = observe_workspace_coverage_managed_process( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - match observation { - WorkspaceCoverageProcessLifecycleObservation::ExactAlive => return Ok(()), - WorkspaceCoverageProcessLifecycleObservation::Inaccessible - | WorkspaceCoverageProcessLifecycleObservation::Indeterminate { .. } => return Ok(()), - WorkspaceCoverageProcessLifecycleObservation::BootSuperseded { .. } - | WorkspaceCoverageProcessLifecycleObservation::ExactExited { .. } - | WorkspaceCoverageProcessLifecycleObservation::Missing - | WorkspaceCoverageProcessLifecycleObservation::Replaced { .. } => {} - } - - if load_workspace_coverage_process_termination_observation( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - )? - .is_none() - { - write_workspace_coverage_process_termination_observation( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - &host, - )?; - } - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - &args.store, - args.runtime_id.clone(), - &latest.launch_id, - host.entry(), - )?; - // Claim acquisition may race the first reconciliation observation. The - // terminal proof is the cut: authenticate Body sight again after it, and - // use only this post-terminal target for replacement/recovery authority. - let post_terminal_target = authenticate_recovery_workspace_coverage_claim_sight( - &args.store, - &runtime_store, - &args.runtime_id, - host.entry(), - )?; - if post_terminal_target - .as_ref() - .is_some_and(|claim| claim.launch_id != latest.launch_id) - { - anyhow::bail!("post-terminal claim sight does not name the terminated managed launch"); - } - let replacement_evidence = CoverageReplacementEvidence { - old_launch_id: latest.launch_id.clone(), - termination_id: termination.termination_id.clone(), - termination_envelope_digest: termination_digest, - }; - let existing_replacement = load_latest_workspace_coverage_managed_process_launch( - &args.store, - args.runtime_id.clone(), - )? - .filter(|launch| { - launch.replaces_launch_id.as_deref() == Some(latest.launch_id.as_str()) - && launch.replaces_termination_id.as_deref() - == Some(termination.termination_id.as_str()) - }); - let replacement = if let Some(existing) = existing_replacement { - existing - } else { - bind_managed_policy(&mut args, &policy); - launch_workspace_coverage_projector(args.clone(), Some(replacement_evidence))? - }; - - let Some(target) = post_terminal_target else { - return Ok(()); - }; - - finish_workspace_coverage_recovery( - &args, - &runtime_store, - host.entry(), - &host, - target, - replacement, - ) -} - -fn finish_workspace_coverage_recovery( - args: &Args, - runtime_store: &Path, - host_identity: &epiphany_core::HostIncarnationIdentityEntry, - host: &epiphany_core::HostIdentitySigner, - target: epiphany_core::WorkspaceCoverageClaimSightEntry, - replacement: WorkspaceCoverageManagedProcessLaunchEntry, -) -> Result<()> { - let ready = (0..100).find_map(|_| { - let observed = load_latest_workspace_coverage_provider_heartbeat( - &args.store, - args.runtime_id.clone(), - &replacement.launch_id, - ) - .ok() - .flatten(); - if let Some(heartbeat) = observed - && heartbeat.status == "ready" - && timestamp_is_fresh(&heartbeat.observed_at_utc).unwrap_or(false) - && authenticate_workspace_coverage_provider_heartbeat( - &args.store, - args.runtime_id.clone(), - &heartbeat.heartbeat_id, - host_identity, - ) - .is_ok() - { - return Some(heartbeat); - } - thread::sleep(StdDuration::from_millis(100)); - None - }); - let Some(ready) = ready else { - anyhow::bail!("workspace coverage replacement did not publish signed readiness in time"); - }; - let actuation_observation = observe_workspace_coverage_managed_process( - &args.store, - args.runtime_id.clone(), - &replacement.launch_id, - host_identity, - )?; - match actuation_observation { - WorkspaceCoverageProcessLifecycleObservation::ExactAlive => { - write_workspace_coverage_recovery_directive( - &args.store, - runtime_store, - &args.runtime_id, - &target, - &replacement.launch_id, - &ready.heartbeat_id, - host, - )?; - } - WorkspaceCoverageProcessLifecycleObservation::Inaccessible - | WorkspaceCoverageProcessLifecycleObservation::Indeterminate { .. } - | WorkspaceCoverageProcessLifecycleObservation::BootSuperseded { .. } - | WorkspaceCoverageProcessLifecycleObservation::ExactExited { .. } - | WorkspaceCoverageProcessLifecycleObservation::Missing - | WorkspaceCoverageProcessLifecycleObservation::Replaced { .. } => {} - } - Ok(()) -} - -fn local_file_sha256(path: &str) -> Option { - if path.trim().is_empty() || path == "none" { - return None; - } - let path = PathBuf::from(path); - if !path.is_file() { - return None; - } - let bytes = fs::read(path).ok()?; - let digest = Sha256::digest(&bytes); - Some(format!("{digest:x}")) -} -fn service_command_path(args: &Args) -> Result { - args.service_command - .clone() - .context("managed service command was not derived from its packaged role") -} - -fn service_lifecycle_receipt( - args: &Args, - action: &str, - status: &str, - command: String, - service_args: Vec, - process_id: Option, - exit_code: Option, - started_at: DateTime, - completed_at: Option>, - operator_artifact_ref: Option, -) -> EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - let receipt_id = format!( - "daemon-service-lifecycle-receipt-{}-{}-{}-{}", - sanitize_id(&args.service_id), - sanitize_id(action), - started_at.timestamp_millis(), - Uuid::new_v4() - ); - EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - .to_string(), - receipt_id, - service_id: args.service_id.clone(), - scheduler_id: "epiphany-daemon-supervisor".to_string(), - runtime_id: args.runtime_id.clone(), - daemon_selector: "*".to_string(), - action: action.to_string(), - status: status.to_string(), - command, - args: service_args, - cwd: args.cwd.as_ref().map(|path| path.display().to_string()), - process_id, - exit_code, - started_at_utc: started_at.to_rfc3339(), - completed_at_utc: completed_at.map(|instant| instant.to_rfc3339()), - operator_artifact_ref: operator_artifact_ref.unwrap_or_else(|| { - format!( - "service://{}/{}", - sanitize_id(&args.service_id), - sanitize_id(action) - ) - }), - private_state_exposed: false, - notes: vec!["Idunn observed this managed-service lifecycle consequence.".to_string()], - executable_sha256: String::new(), - schema_catalog_sha256: String::new(), - preflight_witness_id: String::new(), - required_document_types: Vec::new(), - schema_preflight_passed: false, - managed_policy_id: String::new(), - managed_policy_digest: String::new(), - provider_daemon_id: String::new(), - startup_correlation_id: String::new(), - process_creation_token: 0, - process_created_at_rfc3339: None, - process_executable_path: String::new(), - } -} - -fn assert_swarm_brake_allows_service_lifecycle_entry( - brake: Option<&EpiphanyCultMeshSwarmBrakeEntry>, -) -> Result<()> { - if let Some(brake) = brake - && swarm_brake_blocks_service_lifecycle_entry(Some(brake)) - { - anyhow::bail!( - "local Verse swarm brake engaged; refusing daemon supervisor service lifecycle action; scope={}; protected={}; reason={}", - brake.scope, - brake.protected_surfaces.join(","), - brake.reason - ); - } - Ok(()) -} - -fn swarm_brake_blocks_service_lifecycle_entry( - brake: Option<&EpiphanyCultMeshSwarmBrakeEntry>, -) -> bool { - brake.is_some_and(|brake| { - brake.status == "engaged" - && matches!(brake.scope.as_str(), "swarm" | "all") - && (brake.protected_surfaces.is_empty() - || brake.protected_surfaces.iter().any(|surface| { - surface == "daemon.lifecycle_poke" || surface == "daemon.*" || surface == "*" - })) - }) -} - -fn sanitize_id(raw: &str) -> String { - raw.chars() - .map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '-' }) - .collect() -} - -#[cfg(test)] -mod service_lifecycle_brake_authority_tests { - use super::*; - - fn brake(protected_surfaces: &[&str]) -> EpiphanyCultMeshSwarmBrakeEntry { - EpiphanyCultMeshSwarmBrakeEntry { - schema_version: "epiphany.cultmesh.swarm_brake.v0".into(), - brake_id: "brake-test".into(), - status: "engaged".into(), - scope: "all".into(), - reason: "sleep".into(), - operator_agent_id: "operator".into(), - affected_clusters: vec!["local".into()], - protected_surfaces: protected_surfaces.iter().map(|v| (*v).into()).collect(), - created_at_utc: "2026-07-18T00:00:00Z".into(), - expires_at_utc: None, - private_state_exposed: false, - notes: Vec::new(), - runtime_id: "runtime".into(), - } - } - - #[test] - fn cognitive_scheduler_brake_does_not_claim_service_physiology() { - let cognitive = brake(&[ - "heartbeat.scheduler", - "coordinator.run", - "persona.public_speech", - "daemon.tool_invocation", - ]); - assert!(assert_swarm_brake_allows_service_lifecycle_entry(Some(&cognitive)).is_ok()); - assert!(!swarm_brake_blocks_service_lifecycle_entry(Some( - &cognitive - ))); - assert_eq!(required_managed_health_services(false).len(), 2); - for surface in ["daemon.lifecycle_poke", "daemon.*", "*"] { - let lifecycle = brake(&[surface]); - assert!(assert_swarm_brake_allows_service_lifecycle_entry(Some(&lifecycle)).is_err()); - assert!(swarm_brake_blocks_service_lifecycle_entry(Some(&lifecycle))); - assert!(required_managed_health_services(true).is_empty()); - } - } -} - -#[cfg(test)] -mod supervisor_invariant_tests { - use super::*; - - #[test] - fn idunn_health_configuration_is_explicit_and_all_or_none() { - let endpoint: SocketAddr = "127.0.0.1:17870".parse().unwrap(); - let identity_store = Path::new("provider-health.cc"); - assert!(validate_idunn_health_options(None, None, None, None, None).is_ok()); - assert!( - validate_idunn_health_options( - Some(&endpoint), - Some("yggdrasil-epiphany"), - Some("epiphany.cultnet-rudp-runtime-health"), - Some("deploy-request-test"), - Some(identity_store), - ) - .is_ok() - ); - assert!(validate_idunn_health_options(Some(&endpoint), None, None, None, None).is_err()); - assert!(validate_idunn_health_options(None, Some("epiphany"), None, None, None).is_err()); - assert!( - validate_idunn_health_options( - Some(&endpoint), - Some("yggdrasil-epiphany"), - Some("epiphany.cultnet-rudp-runtime-health"), - Some("deploy-request-test"), - None, - ) - .is_err() - ); - } - - #[test] - fn stale_child_replacement_fails_closed_and_revalidates_process_identity() { - assert!(process_identity_from_parts(Some(7), 0, None, "projector").is_err()); - assert!(process_identity_from_parts(Some(7), 9, None, "").is_err()); - let identity = process_identity_from_parts(Some(7), 9, None, "projector").unwrap(); - assert_eq!(identity.process_id, 7); - assert!( - replacement_identity_from_parts(&ManagedServiceLineage::Pending, Some(7), 0, None, "",) - .unwrap() - .is_none() - ); - assert!( - replacement_identity_from_parts( - &ManagedServiceLineage::Stale("policy mismatch".into()), - Some(7), - 0, - None, - "", - ) - .is_err() - ); - - let mut live = capture_process_instance(std::process::id()).unwrap(); - live.creation_token = live.creation_token.saturating_add(1); - assert!(matches!( - observe_process_instance(&live), - ProcessInstanceObservation::Replaced { .. } - )); - } - - #[test] - fn aggregate_heartbeat_freshness_has_a_bounded_authority_window() { - let now = DateTime::parse_from_rfc3339("2026-07-16T12:03:00Z") - .unwrap() - .with_timezone(&Utc); - assert!(timestamp_is_fresh_at("2026-07-16T12:00:00Z", now).unwrap()); - assert!(!timestamp_is_fresh_at("2026-07-16T11:59:59Z", now).unwrap()); - assert!(!timestamp_is_fresh_at("2026-07-16T12:03:01Z", now).unwrap()); - - let heartbeat = epiphany_core::EpiphanyCultMeshDaemonHeartbeatEventEntry { - schema_version: "epiphany.cultmesh.daemon_heartbeat_event.v0".into(), - heartbeat_id: "heartbeat".into(), - daemon_id: SEMANTIC_PROJECTOR_EXECUTOR_ID.into(), - cluster_id: "local".into(), - provider_incarnation: "provider".into(), - sequence: 1, - status: "ready".into(), - heartbeat_at: "2026-07-16T12:02:00Z".into(), - private_state_exposed: false, - startup_lifecycle_receipt_id: "receipt".into(), - }; - assert!( - !semantic_heartbeat_is_ready(None, "receipt", "2026-07-16T12:00:00Z", now).unwrap() - ); - assert!( - semantic_heartbeat_is_ready(Some(&heartbeat), "receipt", "2026-07-16T12:00:00Z", now,) - .unwrap() - ); - let mut alien = heartbeat.clone(); - alien.startup_lifecycle_receipt_id = "other".into(); - assert!( - !semantic_heartbeat_is_ready(Some(&alien), "receipt", "2026-07-16T12:00:00Z", now,) - .unwrap() - ); - } -} - -#[derive(Clone)] -struct Args { - command: String, - store: PathBuf, - runtime_id: String, - cwd: Option, - force: bool, - disabled: bool, - cooldown_seconds: i64, - service_id: String, - service_command: Option, - service_args: Vec, - loop_interval_seconds: i64, - max_iterations: u64, - receipt_id: Option, - stdout_artifact: Option, - stderr_artifact: Option, - runtime_store: Option, - expected_claim_id: Option, - provider_heartbeat_id: Option, - qdrant_url: Option, - ollama_base_url: Option, - ollama_model: String, - fatal_log: Option, - release_id: Option, - release_witness_sha256: Option, - idunn_rudp_health: Option, - idunn_daemon: Option, - idunn_health_contract: Option, - idunn_deployment_request_id: Option, - idunn_provider_health_identity_store: Option, - idunn_provider_health_public_anchor: Option, - resident_self_store: Option, - resident_provider_stale_seconds: u64, -} - -impl Args { - fn parse() -> Result { - let mut values = env::args().skip(1); - let command = values.next().context("missing supervisor command")?; - let mut store = PathBuf::from(".epiphany-run/cultmesh/local-verse.ccmp"); - let mut store_explicit = false; - let mut runtime_id = "epiphany-local".to_string(); - let mut cwd = None; - let mut force = false; - let mut disabled = false; - let mut cooldown_seconds = 0_i64; - let service_id = String::new(); - let service_command = None; - let service_args = Vec::new(); - let mut loop_interval_seconds = 60_i64; - let mut max_iterations = 0_u64; - let mut receipt_id = None; - let mut stdout_artifact = None; - let mut stderr_artifact = None; - let mut runtime_store = None; - let mut expected_claim_id = None; - let mut provider_heartbeat_id = None; - let mut qdrant_url = None; - let mut ollama_base_url = None; - let mut ollama_model = "qwen3-embedding:0.6b".to_string(); - let mut fatal_log = None; - let mut release_id = None; - let mut release_witness_sha256 = None; - let mut idunn_rudp_health = None; - let mut idunn_daemon = None; - let mut idunn_health_contract = None; - let mut idunn_deployment_request_id = None; - let mut idunn_provider_health_identity_store = None; - let mut idunn_provider_health_public_anchor = None; - let mut resident_self_store = None; - let mut resident_provider_stale_seconds = 180_u64; - - while let Some(arg) = values.next() { - match arg.as_str() { - "--store" => { - store = PathBuf::from(values.next().context("missing --store value")?); - store_explicit = true; - } - "--runtime-id" => { - runtime_id = values.next().context("missing --runtime-id value")? - } - "--cwd" => cwd = Some(PathBuf::from(values.next().context("missing --cwd value")?)), - "--force" => force = true, - "--disabled" => disabled = true, - "--cooldown-seconds" => { - cooldown_seconds = values - .next() - .context("missing --cooldown-seconds value")? - .parse()?; - } - "--loop-interval-seconds" | "--serve-interval-seconds" => { - loop_interval_seconds = values - .next() - .context("missing --loop-interval-seconds value")? - .parse()?; - } - "--max-iterations" => { - max_iterations = values - .next() - .context("missing --max-iterations value")? - .parse()?; - } - "--receipt-id" => { - receipt_id = Some(values.next().context("missing --receipt-id value")?) - } - "--stdout-artifact" => { - stdout_artifact = Some(PathBuf::from( - values.next().context("missing --stdout-artifact value")?, - )); - } - "--stderr-artifact" => { - stderr_artifact = Some(PathBuf::from( - values.next().context("missing --stderr-artifact value")?, - )); - } - "--runtime-store" => { - runtime_store = Some(PathBuf::from( - values.next().context("missing --runtime-store value")?, - )) - } - "--expected-claim-id" => { - expected_claim_id = - Some(values.next().context("missing --expected-claim-id value")?) - } - "--provider-heartbeat-id" => { - provider_heartbeat_id = Some( - values - .next() - .context("missing --provider-heartbeat-id value")?, - ) - } - "--qdrant-url" => { - qdrant_url = Some(values.next().context("missing --qdrant-url value")?) - } - "--ollama-base-url" => { - ollama_base_url = - Some(values.next().context("missing --ollama-base-url value")?) - } - "--ollama-model" => { - ollama_model = values.next().context("missing --ollama-model value")? - } - "--fatal-log" => { - fatal_log = Some(PathBuf::from( - values.next().context("missing --fatal-log value")?, - )); - } - "--release-id" => { - release_id = Some(values.next().context("missing --release-id value")?); - } - "--release-witness-sha256" => { - release_witness_sha256 = Some( - values - .next() - .context("missing --release-witness-sha256 value")?, - ); - } - "--idunn-rudp-health" => { - idunn_rudp_health = Some( - values - .next() - .context("missing --idunn-rudp-health value")? - .parse()?, - ); - } - "--idunn-daemon" => { - idunn_daemon = Some(values.next().context("missing --idunn-daemon value")?); - } - "--idunn-health-contract" => { - idunn_health_contract = Some( - values - .next() - .context("missing --idunn-health-contract value")?, - ); - } - "--idunn-deployment-request-id" => { - idunn_deployment_request_id = Some( - values - .next() - .context("missing --idunn-deployment-request-id value")?, - ); - } - "--idunn-provider-health-identity-store" => { - idunn_provider_health_identity_store = - Some(PathBuf::from(values.next().context( - "missing --idunn-provider-health-identity-store value", - )?)); - } - "--idunn-provider-health-public-anchor" => { - idunn_provider_health_public_anchor = - Some(PathBuf::from(values.next().context( - "missing --idunn-provider-health-public-anchor value", - )?)); - } - "--resident-self-store" => { - resident_self_store = Some(PathBuf::from( - values - .next() - .context("missing --resident-self-store value")?, - )); - } - "--resident-provider-stale-seconds" => { - resident_provider_stale_seconds = values - .next() - .context("missing --resident-provider-stale-seconds value")? - .parse()?; - if resident_provider_stale_seconds == 0 { - anyhow::bail!("--resident-provider-stale-seconds must be positive"); - } - } - other => anyhow::bail!("unknown argument {other:?}"), - } - } - - if !store_explicit && command.contains("smoke") { - store = PathBuf::from(format!( - ".epiphany-smoke/daemon-supervisor-{}/local-verse.ccmp", - sanitize_id(&command) - )); - } - - if loop_interval_seconds < 0 { - anyhow::bail!("--loop-interval-seconds must be non-negative"); - } - if matches!( - command.as_str(), - "provider-health-identity-enroll" | "provider-health-identity-export" - ) { - if [ - idunn_rudp_health.is_some(), - idunn_daemon.is_some(), - idunn_health_contract.is_some(), - idunn_deployment_request_id.is_some(), - ] - .into_iter() - .any(|present| present) - { - anyhow::bail!("provider-health identity commands cannot publish health"); - } - if idunn_provider_health_identity_store.is_none() { - anyhow::bail!( - "provider-health identity command requires --idunn-provider-health-identity-store" - ); - } - if command == "provider-health-identity-enroll" - && idunn_provider_health_public_anchor.is_some() - { - anyhow::bail!( - "provider-health enrollment cannot write a public anchor; use provider-health-identity-export" - ); - } - } else { - validate_idunn_health_options( - idunn_rudp_health.as_ref(), - idunn_daemon.as_deref(), - idunn_health_contract.as_deref(), - idunn_deployment_request_id.as_deref(), - idunn_provider_health_identity_store.as_deref(), - )?; - if idunn_provider_health_public_anchor.is_some() { - anyhow::bail!( - "--idunn-provider-health-public-anchor belongs only to provider-health-identity-export" - ); - } - } - Ok(Self { - command, - store, - runtime_id, - cwd, - force, - disabled, - cooldown_seconds, - service_id, - service_command, - service_args, - loop_interval_seconds, - max_iterations, - receipt_id, - stdout_artifact, - stderr_artifact, - runtime_store, - expected_claim_id, - provider_heartbeat_id, - qdrant_url, - ollama_base_url, - ollama_model, - fatal_log, - release_id, - release_witness_sha256, - idunn_rudp_health, - idunn_daemon, - idunn_health_contract, - idunn_deployment_request_id, - idunn_provider_health_identity_store, - idunn_provider_health_public_anchor, - resident_self_store, - resident_provider_stale_seconds, - }) - } -} - -fn validate_idunn_health_options( - endpoint: Option<&SocketAddr>, - daemon_id: Option<&str>, - health_contract: Option<&str>, - deployment_request_id: Option<&str>, - identity_store: Option<&Path>, -) -> Result<()> { - let fields = [ - endpoint.is_some(), - daemon_id.is_some(), - health_contract.is_some(), - deployment_request_id.is_some(), - identity_store.is_some(), - ]; - if fields.into_iter().any(|present| present) && !fields.into_iter().all(|present| present) { - anyhow::bail!( - "--idunn-rudp-health, --idunn-daemon, --idunn-health-contract, --idunn-deployment-request-id, and --idunn-provider-health-identity-store are all-or-none" - ); - } - for (label, value) in [ - ("--idunn-daemon", daemon_id), - ("--idunn-health-contract", health_contract), - ("--idunn-deployment-request-id", deployment_request_id), - ] { - if value.is_some_and(|value| value.trim().is_empty()) { - anyhow::bail!("{label} cannot be empty"); - } - } - Ok(()) -} diff --git a/epiphany-core/src/bin/epiphany-memory-semantic-projector.rs b/epiphany-core/src/bin/epiphany-memory-semantic-projector.rs deleted file mode 100644 index f75bb0a6..00000000 --- a/epiphany-core/src/bin/epiphany-memory-semantic-projector.rs +++ /dev/null @@ -1,301 +0,0 @@ -use anyhow::{Context, Result, anyhow}; -use epiphany_core::{ - EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION, - EpiphanyCultMeshDaemonHeartbeatEventEntry, EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, - MemorySemanticIndexConfig, MemorySemanticProjectionInput, MemorySemanticProjectorPulseStatus, - SemanticProjectorServiceBody, authenticate_epiphany_cultmesh_semantic_projector_launch, - authorize_memory_semantic_physical_retirements, execute_memory_semantic_physical_retirement, - load_epiphany_cultmesh_daemon_service_lifecycle_receipt, - publish_epiphany_cultmesh_semantic_projection_health, - retain_memory_semantic_projection_lifecycles, write_epiphany_cultmesh_daemon_heartbeat_event, -}; -use serde_json::json; -use sha2::{Digest, Sha256}; -use std::env; -use std::fs; -use std::path::PathBuf; -use std::thread; -use std::time::Duration; -use std::time::Instant; -use uuid::Uuid; - -const DAEMON_ID: &str = "epiphany-memory-semantic-projector"; - -fn main() -> Result<()> { - let args = Args::parse()?; - if args.requires_managed_launch { - if args.startup_lifecycle_receipt_id.trim().is_empty() { - return Err(anyhow!( - "managed projector requires its startup launch receipt id" - )); - } - let receipt = authenticate_managed_launch(&args)?; - if receipt.process_id != Some(std::process::id()) { - return Err(anyhow!( - "managed projector process disagrees with its launch receipt" - )); - } - let executable = env::current_exe().context("failed to resolve projector executable")?; - let executable_sha256 = format!( - "sha256-{:x}", - Sha256::digest(fs::read(&executable).with_context(|| { - format!( - "failed to fingerprint projector executable {}", - executable.display() - ) - })?) - ); - if receipt.executable_sha256 != executable_sha256 { - return Err(anyhow!( - "managed projector executable disagrees with its launch receipt" - )); - } - } - let mut semantic_config = MemorySemanticIndexConfig::from_env(); - semantic_config.qdrant_url = args.qdrant_url.clone(); - semantic_config.ollama_base_url = args.ollama_base_url.clone(); - semantic_config.ollama_model = args.ollama_model.clone(); - let projector = - SemanticProjectorServiceBody::new(&args.runtime_store, semantic_config.clone())?; - let provider_incarnation = projector.provider_incarnation().to_string(); - let mut sequence = 0_u64; - loop { - sequence = sequence.saturating_add(1); - let pulse = projector.pulse(); - let outcome = pulse.outcome; - let inputs = pulse.inputs; - let source_faults = pulse.source_fault_count; - let mut retention_faults = Vec::new(); - let mut retention_mutation_count = 0_u32; - for input in &inputs { - let store = source_store(&args, input)?; - match authorize_memory_semantic_physical_retirements( - store, - input, - args.retained_generations, - &chrono::Utc::now().to_rfc3339(), - ) { - Ok(retirements) => { - for retirement in retirements { - if let Err(error) = execute_memory_semantic_physical_retirement( - store, - input, - &retirement.retirement_id, - &semantic_config, - &chrono::Utc::now().to_rfc3339(), - ) { - retention_faults.push(format!( - "{} physical: {error:#}", - input.obligation().partition - )); - } - } - } - Err(error) => retention_faults.push(format!( - "{} physical authorization: {error:#}", - input.obligation().partition - )), - } - match retain_memory_semantic_projection_lifecycles( - store, - input, - args.retained_generations, - &chrono::Utc::now().to_rfc3339(), - ) { - Ok(Some(_)) => retention_mutation_count += 1, - Ok(None) => {} - Err(error) => { - retention_faults.push(format!("{}: {error:#}", input.obligation().partition)) - } - } - } - let retention_fault_count = retention_faults.len() as u32; - let mut health_publication_faults = Vec::new(); - for input in &inputs { - let store = source_store(&args, input)?; - if let Err(error) = publish_epiphany_cultmesh_semantic_projection_health( - &args.local_verse_store, - args.runtime_id.clone(), - store, - input, - &provider_incarnation, - ) { - health_publication_faults - .push(format!("{}: {error:#}", input.obligation().partition)); - } - } - let health_faults = health_publication_faults.len() as u32; - let degraded = source_faults > 0 - || retention_fault_count > 0 - || health_faults > 0 - || matches!( - outcome.status, - MemorySemanticProjectorPulseStatus::Contended - | MemorySemanticProjectorPulseStatus::Refused - ); - let heartbeat = write_epiphany_cultmesh_daemon_heartbeat_event( - &args.local_verse_store, - args.runtime_id.clone(), - EpiphanyCultMeshDaemonHeartbeatEventEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION.to_string(), - heartbeat_id: Uuid::new_v4().to_string(), - daemon_id: DAEMON_ID.to_string(), - cluster_id: "local".to_string(), - provider_incarnation: provider_incarnation.clone(), - sequence, - status: if degraded { "degraded" } else { "ready" }.to_string(), - heartbeat_at: chrono::Utc::now().to_rfc3339(), - private_state_exposed: false, - startup_lifecycle_receipt_id: args.startup_lifecycle_receipt_id.clone(), - }, - )?; - println!( - "{}", - serde_json::to_string(&json!({ - "schemaVersion": "epiphany.memory_semantic_projector_pulse.v0", - "pulseSequence": sequence, - "providerIncarnation": provider_incarnation, - "heartbeatId": heartbeat.heartbeat_id, - "providerStatus": heartbeat.status, - "pulseStatus": pulse_status(outcome.status), - "inspectedSourceCount": outcome.inspections.len(), - "sourceFaultCount": source_faults, - "retentionMutationCount": retention_mutation_count, - "retentionFaultCount": retention_fault_count, - "retentionFaults": retention_faults, - "healthPublicationFaultCount": health_faults, - "healthPublicationFaults": health_publication_faults, - "selectedScopeId": outcome.selected_scope_id, - "privateStateExposed": false, - "authoritative": false - }))? - ); - if args.max_iterations != 0 && sequence >= args.max_iterations { - break; - } - thread::sleep(Duration::from_secs(args.interval_seconds)); - } - Ok(()) -} - -fn authenticate_managed_launch( - args: &Args, -) -> Result { - let deadline = Instant::now() + Duration::from_secs(5); - loop { - if load_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &args.local_verse_store, - args.runtime_id.clone(), - &args.startup_lifecycle_receipt_id, - )? - .is_some() - { - return authenticate_epiphany_cultmesh_semantic_projector_launch( - &args.local_verse_store, - args.runtime_id.clone(), - &args.startup_lifecycle_receipt_id, - ); - } - if Instant::now() >= deadline { - return Err(anyhow!( - "managed projector startup launch receipt was not persisted" - )); - } - thread::sleep(Duration::from_millis(20)); - } -} - -fn source_store<'a>(args: &'a Args, input: &MemorySemanticProjectionInput) -> Result<&'a PathBuf> { - match input.obligation().partition.as_str() { - "modeling" => Ok(&args.runtime_store), - other => Err(anyhow!( - "unsupported semantic projection partition {other:?}" - )), - } -} - -fn pulse_status(status: MemorySemanticProjectorPulseStatus) -> &'static str { - match status { - MemorySemanticProjectorPulseStatus::Idle => "idle", - MemorySemanticProjectorPulseStatus::Executed => "executed", - MemorySemanticProjectorPulseStatus::Contended => "contended", - MemorySemanticProjectorPulseStatus::Refused => "refused", - MemorySemanticProjectorPulseStatus::Busy => "busy", - } -} - -struct Args { - runtime_store: PathBuf, - local_verse_store: PathBuf, - runtime_id: String, - interval_seconds: u64, - max_iterations: u64, - retained_generations: usize, - startup_lifecycle_receipt_id: String, - qdrant_url: String, - ollama_base_url: String, - ollama_model: String, - requires_managed_launch: bool, -} - -impl Args { - fn parse() -> Result { - let mut values = env::args().skip(1); - let command = values.next().unwrap_or_else(|| "pulse".to_string()); - if !matches!(command.as_str(), "pulse" | "once" | "serve" | "daemon") { - return Err(anyhow!("unknown command {command:?}; use pulse or serve")); - } - let mut runtime_store = None; - let mut local_verse_store = None; - let mut runtime_id = "epiphany-local".to_string(); - let mut interval_seconds = 60_u64; - let mut max_iterations = if matches!(command.as_str(), "pulse" | "once") { - 1 - } else { - 0 - }; - let mut retained_generations = 256_usize; - let mut qdrant_url = None; - let mut ollama_base_url = None; - let mut ollama_model = "qwen3-embedding:0.6b".to_string(); - while let Some(flag) = values.next() { - let mut value = || { - values - .next() - .with_context(|| format!("missing value for {flag}")) - }; - match flag.as_str() { - "--runtime-store" => runtime_store = Some(PathBuf::from(value()?)), - "--local-verse-store" => local_verse_store = Some(PathBuf::from(value()?)), - "--runtime-id" => runtime_id = value()?, - "--interval-seconds" => interval_seconds = value()?.parse()?, - "--max-iterations" => max_iterations = value()?.parse()?, - "--retained-generations" => retained_generations = value()?.parse()?, - "--qdrant-url" => qdrant_url = Some(value()?), - "--ollama-base-url" => ollama_base_url = Some(value()?), - "--ollama-model" => ollama_model = value()?, - _ => return Err(anyhow!("unexpected argument {flag:?}")), - } - } - if interval_seconds == 0 { - return Err(anyhow!("--interval-seconds must be positive")); - } - if retained_generations == 0 { - return Err(anyhow!("--retained-generations must be positive")); - } - Ok(Self { - runtime_store: runtime_store.context("missing --runtime-store")?, - local_verse_store: local_verse_store.context("missing --local-verse-store")?, - runtime_id, - interval_seconds, - max_iterations, - retained_generations, - startup_lifecycle_receipt_id: env::var("EPIPHANY_STARTUP_LIFECYCLE_RECEIPT_ID") - .unwrap_or_default(), - qdrant_url: qdrant_url.context("missing --qdrant-url")?, - ollama_base_url: ollama_base_url.context("missing --ollama-base-url")?, - ollama_model, - requires_managed_launch: matches!(command.as_str(), "serve" | "daemon"), - }) - } -} diff --git a/epiphany-core/src/bin/epiphany-memory-semantic.rs b/epiphany-core/src/bin/epiphany-memory-semantic.rs deleted file mode 100644 index 77ff5ee5..00000000 --- a/epiphany-core/src/bin/epiphany-memory-semantic.rs +++ /dev/null @@ -1,258 +0,0 @@ -use anyhow::{Context, Result, anyhow}; -use epiphany_core::{ - EpiphanyMemoryContextQuery, EpiphanyMemoryGraphSnapshot, MemorySemanticIndexConfig, - MemorySemanticProjectionInput, WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, - WorkspaceCoveragePolicy, WorkspaceProjectionIdentity, - load_memory_semantic_projection_readiness, observe_repository_readiness, - publish_epiphany_cultmesh_semantic_projection_health, - runtime_modeling_semantic_projection_input, semantic_memory_context, -}; -use std::env; -use std::path::PathBuf; - -fn main() -> Result<()> { - let mut args = env::args().skip(1); - let command = args.next().ok_or_else(|| usage_error("missing command"))?; - let options = Options::parse(args)?; - let config = MemorySemanticIndexConfig::from_env(); - match command.as_str() { - "health" => { - let (input, source_store) = options.load_projection_input()?; - let verse_store = options - .local_verse_store - .as_ref() - .ok_or_else(|| usage_error("health requires --local-verse-store "))?; - let health = publish_epiphany_cultmesh_semantic_projection_health( - verse_store, - options.runtime_id.clone(), - source_store, - &input, - options.provider_incarnation()?, - )?; - print_semantic_health(&health)?; - } - "context" => { - let (snapshot, swarm_id) = options.load_source()?; - let text = options - .text - .clone() - .ok_or_else(|| usage_error("context requires --text "))?; - let projection_input = options.load_projection_input().ok().map(|(input, _)| input); - let readiness = match (&projection_input, options.source_store()) { - (Some(input), Some(store)) => { - load_memory_semantic_projection_readiness(store, input)? - } - _ => None, - }; - let packet = semantic_memory_context( - &snapshot, - &swarm_id, - &EpiphanyMemoryContextQuery { - id: options - .query_id - .clone() - .unwrap_or_else(|| "memory-semantic-context".to_string()), - profile: options.profile, - text: Some(text), - budget: options.budget, - ..Default::default() - }, - readiness.as_ref(), - &config, - ); - print_json(&packet)?; - } - "repository-readiness" => { - let runtime_store = options.runtime_store.as_ref().ok_or_else(|| { - usage_error("repository-readiness requires --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(()) -} - -struct Options { - runtime_store: Option, - local_verse_store: Option, - runtime_id: String, - provider_incarnation: Option, - swarm_id: Option, - text: Option, - query_id: Option, - budget: Option, - profile: Option, - workspace_embedding_provider_id: Option, - workspace_embedding_model: Option, - workspace_vector_dimensions: Option, -} - -impl Options { - fn parse(args: impl Iterator) -> Result { - let mut options = Self { - runtime_store: None, - local_verse_store: None, - runtime_id: "epiphany-memory-semantic".to_string(), - provider_incarnation: None, - swarm_id: None, - text: None, - 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() { - let mut value = || { - args.next() - .with_context(|| format!("missing value for {flag}")) - }; - match flag.as_str() { - "--runtime-store" => options.runtime_store = Some(PathBuf::from(value()?)), - "--local-verse-store" => options.local_verse_store = Some(PathBuf::from(value()?)), - "--runtime-id" => options.runtime_id = value()?, - "--provider-incarnation" => options.provider_incarnation = Some(value()?), - "--swarm-id" => options.swarm_id = Some(value()?), - "--text" => options.text = Some(value()?), - "--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:?}"))), - } - } - if options - .swarm_id - .as_ref() - .is_some_and(|id| id.trim().is_empty()) - { - return Err(usage_error("--swarm-id must not be empty")); - } - if options.runtime_store.is_none() { - return Err(usage_error("provide --runtime-store")); - } - Ok(options) - } - - fn load_source(&self) -> Result<(EpiphanyMemoryGraphSnapshot, String)> { - let (input, _) = self.load_projection_input()?; - Ok(( - input.snapshot().clone(), - input.obligation().swarm_id.clone(), - )) - } - - fn load_projection_input(&self) -> Result<(MemorySemanticProjectionInput, &PathBuf)> { - let store = self - .runtime_store - .as_ref() - .ok_or_else(|| anyhow!("semantic projection requires the runtime store"))?; - let input = runtime_modeling_semantic_projection_input(store)?; - if self - .swarm_id - .as_ref() - .is_some_and(|claimed| claimed != &input.obligation().swarm_id) - { - return Err(anyhow!( - "--swarm-id does not match canonical source identity" - )); - } - Ok((input, store)) - } - - fn source_store(&self) -> Option<&PathBuf> { - self.runtime_store.as_ref() - } - - fn provider_incarnation(&self) -> Result<&str> { - self.provider_incarnation - .as_deref() - .filter(|value| !value.trim().is_empty()) - .ok_or_else(|| { - usage_error("CultMesh health publication requires --provider-incarnation ") - }) - } -} - -fn parse_profile(value: &str) -> Result { - serde_json::from_str(&format!("\"{value}\"")) - .with_context(|| format!("unknown memory profile {value:?}")) -} - -fn usage_error(message: &str) -> anyhow::Error { - anyhow!( - "{message}\nusage: epiphany-memory-semantic --runtime-store [--swarm-id ] [--local-verse-store --runtime-id --provider-incarnation ] [--text ] [--query-id ] [--budget ] [--profile ] [--workspace-embedding-provider-id --workspace-embedding-model --workspace-vector-dimensions ]" - ) -} - -fn print_json(value: &impl serde::Serialize) -> Result<()> { - println!("{}", serde_json::to_string_pretty(value)?); - Ok(()) -} - -fn print_semantic_health( - health: &epiphany_core::EpiphanyCultMeshSemanticProjectionHealthEntry, -) -> Result<()> { - print_json(&serde_json::json!({ - "schemaVersion": health.schema_version, - "verseId": health.verse_id, - "verseTier": health.verse_tier, - "swarmId": health.swarm_id, - "partition": health.partition, - "obligationId": health.obligation_id, - "sourceGeneration": health.source_generation, - "canonicalModelHash": health.canonical_model_hash, - "canonicalContentSetHash": health.canonical_content_set_hash, - "status": health.status, - "receiptId": health.receipt_id, - "indexedDocumentCount": health.indexed_document_count, - "vectorDimensions": health.vector_dimensions, - "observedAt": health.observed_at, - "observedSourceAt": health.observed_source_at, - "providerId": health.provider_id, - "providerIncarnation": health.provider_incarnation, - "authoritative": health.authoritative, - "nonAuthoritative": !health.authoritative, - "authority": "sight-only", - "queryEligibleDisplayOnly": health.query_eligible_display_only, - "privateStateExposed": health.private_state_exposed, - })) -} diff --git a/epiphany-core/src/bin/epiphany-repository-body.rs b/epiphany-core/src/bin/epiphany-repository-body.rs index 2069988b..6e8cd944 100644 --- a/epiphany-core/src/bin/epiphany-repository-body.rs +++ b/epiphany-core/src/bin/epiphany-repository-body.rs @@ -5,7 +5,7 @@ use epiphany_core::{ EpiphanyMemoryNodeKind, EpiphanyMemoryProfile, EpiphanyRepoModelSeed, EpiphanyRepoModelSeedDocuments, ObserveOutcome, RuntimeSpineInitOptions, admit_repository_body_observation, bind_repository_body, bind_runtime_to_swarm, - bind_runtime_workspace_coverage_store, initialize_keyed_repo_model, initialize_runtime_spine, + initialize_keyed_repo_model, initialize_runtime_spine, load_current_runtime_repository_body_basis, load_repository_body_status, observe_repository_body, }; @@ -21,8 +21,6 @@ fn main() -> Result<()> { let repo = PathBuf::from(required(&args, "--repo")?); let store = PathBuf::from(required(&args, "--store")?); let runtime_store = PathBuf::from(required(&args, "--runtime-store")?); - let workspace_coverage_store = - PathBuf::from(required(&args, "--workspace-coverage-store")?); let workspace_id = required(&args, "--workspace-id")?; let runtime_id = required(&args, "--runtime-id")?; let swarm_id = required(&args, "--swarm-id")?; @@ -37,7 +35,6 @@ fn main() -> Result<()> { )?; bind_runtime_to_swarm(&runtime_store, swarm_id, &at)?; let binding = bind_repository_body(&repo, &store, &runtime_store, workspace_id)?; - bind_runtime_workspace_coverage_store(&runtime_store, &workspace_coverage_store, &at)?; observe_repository_body(&repo, &store, &runtime_store)?; let body_basis = load_current_runtime_repository_body_basis(&runtime_store)?; admit_repository_body_observation(&runtime_store, &body_basis)?; @@ -173,7 +170,7 @@ fn required<'a>(args: &'a [String], name: &str) -> Result<&'a str> { } fn usage() -> Result { bail!( - "usage: epiphany-repository-body bootstrap --repo PATH --store PATH --runtime-store PATH --workspace-coverage-store PATH --workspace-id ID --runtime-id ID --swarm-id ID | bind --repo PATH --store PATH --runtime-store PATH --workspace-id ID | observe --repo PATH --store PATH --runtime-store PATH | status --store PATH | smoke" + "usage: epiphany-repository-body bootstrap --repo PATH --store PATH --runtime-store PATH --workspace-id ID --runtime-id ID --swarm-id ID | bind --repo PATH --store PATH --runtime-store PATH --workspace-id ID | observe --repo PATH --store PATH --runtime-store PATH | status --store PATH | smoke" ) } fn smoke() -> Result<()> { @@ -183,7 +180,6 @@ fn smoke() -> Result<()> { uuid::Uuid::new_v4() )); let runtime_store = store.with_extension("runtime.cc"); - let workspace_coverage_store = store.with_extension("workspace-coverage.cc"); initialize_runtime_spine( &runtime_store, RuntimeSpineInitOptions { @@ -203,11 +199,6 @@ fn smoke() -> Result<()> { &runtime_store, "epiphany-repository-body-smoke", )?; - bind_runtime_workspace_coverage_store( - &runtime_store, - &workspace_coverage_store, - "2026-07-15T00:00:02Z", - )?; let outcome = observe_repository_body(&root, &store, &runtime_store)?; let basis = load_current_runtime_repository_body_basis(&runtime_store)?; admit_repository_body_observation(&runtime_store, &basis)?; @@ -215,8 +206,6 @@ fn smoke() -> Result<()> { .ok_or_else(|| anyhow::anyhow!("smoke observation missing after commit"))?; std::fs::remove_file(&store)?; std::fs::remove_file(&runtime_store)?; - std::fs::remove_file(&workspace_coverage_store)?; - let _ = std::fs::remove_file(workspace_coverage_store.with_extension("cc.lock")); let generation = match outcome { ObserveOutcome::Created(value) | ObserveOutcome::Unchanged(value) => value.generation, }; diff --git a/epiphany-core/src/bin/epiphany-workspace-coverage-projector.rs b/epiphany-core/src/bin/epiphany-workspace-coverage-projector.rs deleted file mode 100644 index d28ed7b4..00000000 --- a/epiphany-core/src/bin/epiphany-workspace-coverage-projector.rs +++ /dev/null @@ -1,370 +0,0 @@ -use anyhow::{Context, Result, anyhow}; -use ed25519_dalek::SigningKey; -use epiphany_core::{ - WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION, - WorkspaceCoverageManagedProcessLaunchEntry, WorkspaceCoverageProjectorConfig, - WorkspaceCoverageProjectorPulseStatus, WorkspaceCoverageProjectorServiceBody, - WorkspaceCoverageProviderHeartbeatEntry, - authenticate_workspace_coverage_managed_process_launch, capture_process_instance, - load_workspace_coverage_managed_process_launch, - load_workspace_coverage_managed_process_launch_with_digest, native_boot_identity, - open_default_host_identity, read_workspace_coverage_process_bootstrap, - sign_workspace_coverage_heartbeat, write_workspace_coverage_provider_heartbeat, -}; -use serde_json::json; -use std::env; -use std::io; -use std::path::PathBuf; -use std::sync::{Arc, Mutex}; -use std::thread; -use std::time::{Duration, Instant}; -use uuid::Uuid; -use zeroize::Zeroize; - -fn main() -> Result<()> { - let args = Args::parse()?; - let mut bootstrap = read_workspace_coverage_process_bootstrap(io::stdin().lock())?; - if bootstrap.launch_id.to_string() != args.managed_process_launch_id { - return Err(anyhow!( - "bootstrap launch id disagrees with launch environment" - )); - } - let provider_key = SigningKey::from_bytes(&bootstrap.provider_signing_seed); - bootstrap.provider_signing_seed.zeroize(); - let (launch, launch_digest) = authenticate_managed_launch(&args, &provider_key)?; - - let mut config = WorkspaceCoverageProjectorConfig::from_env(); - config.qdrant_url = args.qdrant_url.clone(); - config.ollama_base_url = args.ollama_base_url.clone(); - config.ollama_model = args.ollama_model.clone(); - let mut projector = WorkspaceCoverageProjectorServiceBody::new( - &args.runtime_store, - &args.runtime_id, - config, - &launch.provider_incarnation_id, - &launch.launch_id, - )?; - let trusted_host = open_default_host_identity()?; - projector.install_execution_authority( - &args.local_verse_store, - &args.runtime_id, - trusted_host.entry().clone(), - provider_key.clone(), - )?; - - let first_heartbeat = publish_heartbeat(&args, &launch, &launch_digest, &provider_key, 1)?; - let latest_heartbeat = Arc::new(Mutex::new(HeartbeatProjection { - heartbeat_id: first_heartbeat.heartbeat_id, - provider_status: first_heartbeat.status, - })); - spawn_heartbeat_nerve( - &args, - &launch, - &launch_digest, - &provider_key, - Arc::clone(&latest_heartbeat), - )?; - - let mut pulse_sequence = 0_u64; - loop { - pulse_sequence = pulse_sequence - .checked_add(1) - .ok_or_else(|| anyhow!("workspace coverage pulse sequence exhausted"))?; - let pulse = projector.pulse(); - let heartbeat = latest_heartbeat - .lock() - .map_err(|_| anyhow!("workspace coverage heartbeat projection lock poisoned"))? - .clone(); - println!( - "{}", - serde_json::to_string(&json!({ - "schemaVersion": "epiphany.workspace_coverage_projector_pulse.v0", - "pulseSequence": pulse_sequence, - "providerIncarnation": projector.provider_incarnation(), - "heartbeatId": heartbeat.heartbeat_id, - "providerStatus": heartbeat.provider_status, - "pulseStatus": pulse_status(pulse.status), - "bodyObservationId": pulse.body_observation_id, - "bodyGeneration": pulse.body_generation, - "planId": pulse.plan_id, - "receiptId": pulse.receipt_id, - "fault": pulse.fault, - "privateStateExposed": false, - "authoritative": false - }))? - ); - thread::sleep(Duration::from_secs(args.interval_seconds)); - } -} - -#[derive(Clone)] -struct HeartbeatProjection { - heartbeat_id: String, - provider_status: String, -} - -fn spawn_heartbeat_nerve( - args: &Args, - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - launch_digest: &str, - provider_key: &SigningKey, - latest: Arc>, -) -> Result<()> { - let local_verse_store = args.local_verse_store.clone(); - let runtime_id = args.runtime_id.clone(); - let interval = Duration::from_secs(args.heartbeat_interval_seconds); - let launch = launch.clone(); - let launch_digest = launch_digest.to_string(); - let provider_key = provider_key.clone(); - thread::Builder::new() - .name("workspace-coverage-heartbeat".into()) - .spawn(move || { - let mut sequence = 1_u64; - loop { - thread::sleep(interval); - sequence = match sequence.checked_add(1) { - Some(sequence) => sequence, - None => { - fatal_heartbeat_nerve("workspace coverage heartbeat sequence exhausted"); - } - }; - let heartbeat = match publish_heartbeat_to( - &local_verse_store, - &runtime_id, - &launch, - &launch_digest, - &provider_key, - sequence, - ) { - Ok(heartbeat) => heartbeat, - Err(error) => { - fatal_heartbeat_nerve(&format!( - "workspace coverage heartbeat publication failed: {error:#}" - )); - } - }; - match latest.lock() { - Ok(mut projection) => { - projection.heartbeat_id = heartbeat.heartbeat_id; - projection.provider_status = heartbeat.status; - } - Err(_) => { - fatal_heartbeat_nerve( - "workspace coverage heartbeat projection lock poisoned", - ); - } - } - } - }) - .context("failed to start workspace coverage heartbeat nerve")?; - Ok(()) -} - -fn fatal_heartbeat_nerve(message: &str) -> ! { - eprintln!("{message}"); - // This exact process owns both projection and its authenticated liveness - // publisher. Continuing after the nerve dies would leave an unfenced - // actuator relying on an external repair loop to notice the corpse. - std::process::exit(1) -} - -fn publish_heartbeat( - args: &Args, - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - launch_digest: &str, - provider_key: &SigningKey, - sequence: u64, -) -> Result { - publish_heartbeat_to( - &args.local_verse_store, - &args.runtime_id, - launch, - launch_digest, - provider_key, - sequence, - ) -} - -fn publish_heartbeat_to( - local_verse_store: &PathBuf, - runtime_id: &str, - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - launch_digest: &str, - provider_key: &SigningKey, - sequence: u64, -) -> Result { - let mut heartbeat = WorkspaceCoverageProviderHeartbeatEntry { - schema_version: WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION.to_string(), - heartbeat_id: Uuid::new_v4().to_string(), - launch_id: launch.launch_id.clone(), - launch_envelope_digest: launch_digest.to_string(), - service_id: launch.service_id.clone(), - provider_daemon_id: launch.provider_daemon_id.clone(), - runtime_id: launch.runtime_id.clone(), - host_identity_id: launch.host_identity_id.clone(), - host_identity_record_digest: launch.host_identity_record_digest.clone(), - boot_identity: launch.boot_identity.clone(), - process_id: launch.process_id, - process_creation_token: launch.process_creation_token, - process_executable_path: launch.process_executable_path.clone(), - provider_incarnation_id: launch.provider_incarnation_id.clone(), - provider_public_key: launch.provider_public_key.clone(), - sequence, - // Heartbeat proves only that this exact provider process remains able - // to publish. Projection faults and progress belong to separate state. - status: "ready".to_string(), - observed_at_utc: chrono::Utc::now().to_rfc3339(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".to_string(), - }; - sign_workspace_coverage_heartbeat(&mut heartbeat, provider_key)?; - write_workspace_coverage_provider_heartbeat( - local_verse_store, - runtime_id.to_string(), - heartbeat, - ) -} - -fn authenticate_managed_launch( - args: &Args, - provider_key: &SigningKey, -) -> Result<(WorkspaceCoverageManagedProcessLaunchEntry, String)> { - let host = open_default_host_identity()?; - let deadline = Instant::now() + Duration::from_secs(5); - loop { - if load_workspace_coverage_managed_process_launch( - &args.local_verse_store, - args.runtime_id.clone(), - &args.managed_process_launch_id, - )? - .is_some() - { - let launch = authenticate_workspace_coverage_managed_process_launch( - &args.local_verse_store, - args.runtime_id.clone(), - &args.managed_process_launch_id, - host.entry(), - )?; - let own = capture_process_instance(std::process::id())?; - let boot = native_boot_identity() - .ok_or_else(|| anyhow!("native boot identity is not provable"))?; - if launch.boot_identity != boot - || launch.process_id != own.process_id - || launch.process_creation_token != own.creation_token - || PathBuf::from(&launch.process_executable_path) != own.executable_path - || launch.provider_public_key != provider_key.verifying_key().to_bytes() - { - return Err(anyhow!( - "managed launch disagrees with this exact provider process" - )); - } - let (_, digest) = load_workspace_coverage_managed_process_launch_with_digest( - &args.local_verse_store, - args.runtime_id.clone(), - &args.managed_process_launch_id, - )? - .ok_or_else(|| anyhow!("managed launch disappeared"))?; - return Ok((launch, digest)); - } - if Instant::now() >= deadline { - return Err(anyhow!( - "managed workspace coverage projector launch was not persisted" - )); - } - thread::sleep(Duration::from_millis(20)); - } -} - -fn pulse_status(status: WorkspaceCoverageProjectorPulseStatus) -> &'static str { - match status { - WorkspaceCoverageProjectorPulseStatus::Idle => "idle", - WorkspaceCoverageProjectorPulseStatus::Executed => "executed", - WorkspaceCoverageProjectorPulseStatus::Contended => "contended", - WorkspaceCoverageProjectorPulseStatus::Refused => "refused", - } -} - -struct Args { - runtime_store: PathBuf, - local_verse_store: PathBuf, - runtime_id: String, - interval_seconds: u64, - heartbeat_interval_seconds: u64, - managed_process_launch_id: String, - qdrant_url: String, - ollama_base_url: String, - ollama_model: String, -} - -impl Args { - fn parse() -> Result { - let mut values = env::args().skip(1); - let command = values.next().context("missing command; use serve")?; - if command != "serve" { - return Err(anyhow!("unknown command {command:?}; use serve")); - } - let mut runtime_store = None; - let mut local_verse_store = None; - let mut runtime_id = None; - let mut interval_seconds = None; - let mut heartbeat_interval_seconds = None; - let mut qdrant_url = None; - let mut ollama_base_url = None; - let mut ollama_model = None; - while let Some(flag) = values.next() { - let mut value = || { - values - .next() - .with_context(|| format!("missing value for {flag}")) - }; - match flag.as_str() { - "--runtime-store" => runtime_store = Some(PathBuf::from(value()?)), - "--local-verse-store" => local_verse_store = Some(PathBuf::from(value()?)), - "--runtime-id" => runtime_id = Some(value()?), - "--interval-seconds" => interval_seconds = Some(value()?.parse::()?), - "--heartbeat-interval-seconds" => { - heartbeat_interval_seconds = Some(value()?.parse::()?) - } - "--qdrant-url" => qdrant_url = Some(value()?), - "--ollama-base-url" => ollama_base_url = Some(value()?), - "--ollama-model" => ollama_model = Some(value()?), - _ => return Err(anyhow!("unexpected argument {flag:?}")), - } - } - let interval_seconds = interval_seconds.context("missing --interval-seconds")?; - if interval_seconds == 0 { - return Err(anyhow!("--interval-seconds must be positive")); - } - let heartbeat_interval_seconds = - heartbeat_interval_seconds.context("missing --heartbeat-interval-seconds")?; - if heartbeat_interval_seconds == 0 { - return Err(anyhow!("--heartbeat-interval-seconds must be positive")); - } - let managed_process_launch_id = - env::var("EPIPHANY_WORKSPACE_COVERAGE_LAUNCH_ID").unwrap_or_default(); - if managed_process_launch_id.trim().is_empty() { - return Err(anyhow!( - "managed workspace coverage projector requires its managed process launch id" - )); - } - Ok(Self { - runtime_store: runtime_store.context("missing --runtime-store")?, - local_verse_store: local_verse_store.context("missing --local-verse-store")?, - runtime_id: runtime_id.context("missing --runtime-id")?, - interval_seconds, - heartbeat_interval_seconds, - managed_process_launch_id, - qdrant_url: required_nonempty(qdrant_url, "--qdrant-url")?, - ollama_base_url: required_nonempty(ollama_base_url, "--ollama-base-url")?, - ollama_model: required_nonempty(ollama_model, "--ollama-model")?, - }) - } -} - -fn required_nonempty(value: Option, flag: &str) -> Result { - let value = value.with_context(|| format!("missing {flag}"))?; - if value.trim().is_empty() { - return Err(anyhow!("{flag} must not be empty")); - } - Ok(value) -} diff --git a/epiphany-core/src/cultmesh_integration.rs b/epiphany-core/src/cultmesh_integration.rs index 40a01b20..a91efbd6 100644 --- a/epiphany-core/src/cultmesh_integration.rs +++ b/epiphany-core/src/cultmesh_integration.rs @@ -1,238 +1,15 @@ use crate::packaged_release::{EpiphanyPackagedReleaseEntry, EpiphanyPackagedReleaseHead}; -use crate::workspace_coverage_process_documents::{ - WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION, - WORKSPACE_COVERAGE_CLAIM_SIGHT_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROCESS_TERMINATION_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION, - WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_SCHEMA_VERSION, - WORKSPACE_COVERAGE_TERMINAL_SIGHT_SCHEMA_VERSION, WorkspaceCoverageAdvancementSightEntry, - WorkspaceCoverageClaimSightEntry, WorkspaceCoverageManagedProcessLaunchEntry, - WorkspaceCoverageProcessEvidenceHead, WorkspaceCoverageProcessTerminationObservationEntry, - WorkspaceCoverageProviderHeartbeatEntry, WorkspaceCoverageRecoveryDirectiveEntry, - WorkspaceCoverageTerminalSightEntry, -}; -use crate::workspace_coverage_projection_progress::{ - WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION, WorkspaceCoverageProjectionProgressEntry, -}; -use anyhow::Context; -use anyhow::Result; -use anyhow::anyhow; -use chrono::DateTime; -use chrono::Utc; -use cultcache_rs::CacheBackingStore; +use anyhow::{Result, anyhow}; use cultcache_rs::DatabaseEntry; -use cultcache_rs::SingleFileMessagePackBackingStore; -use cultmesh_rs::CultMesh; -use cultmesh_rs::CultMeshNode; -use cultmesh_rs::CultMeshNodeOptions; -use cultmesh_rs::cultmesh_documents; -use sha2::Digest; -use sha2::Sha256; +use cultmesh_rs::{CultMesh, CultMeshNode, CultMeshNodeOptions, cultmesh_documents}; use std::path::Path; -use uuid::Uuid; -pub const EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_TYPE: &str = - "epiphany.cultmesh.daemon_heartbeat_event"; -pub const EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION: &str = - "epiphany.cultmesh.daemon_heartbeat_event.v1"; -pub const EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_TYPE: &str = - "epiphany.cultmesh.daemon_service_lifecycle_receipt"; -pub const EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION: &str = - "epiphany.cultmesh.daemon_service_lifecycle_receipt.v2"; -pub const EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_TYPE: &str = - "epiphany.cultmesh.managed_service_policy"; -pub const EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION: &str = - "epiphany.cultmesh.managed_service_policy.v1"; -const EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID: &str = "epiphany-memory-semantic-projector-service"; -pub const EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID: &str = - "epiphany-workspace-coverage-projector-service"; -pub const EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID: &str = - "epiphany-workspace-coverage-projector"; pub const EPIPHANY_CULTMESH_SWARM_BRAKE_TYPE: &str = "epiphany.cultmesh.swarm_brake"; -pub const EPIPHANY_CULTMESH_SWARM_BRAKE_SCHEMA_VERSION: &str = "epiphany.cultmesh.swarm_brake.v0"; +pub const EPIPHANY_CULTMESH_SWARM_BRAKE_SCHEMA_VERSION: &str = + "epiphany.cultmesh.swarm_brake.v0"; pub const EPIPHANY_CULTMESH_SWARM_BRAKE_KEY: &str = "epiphany-local/swarm-brake"; -pub const EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID: &str = "gamecult-local"; -pub const EPIPHANY_CULTMESH_LOCAL_AREA_TIER: &str = "local-area"; -pub const EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_TYPE: &str = - "epiphany.cultmesh.semantic_projection_health"; -pub const EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_SCHEMA_VERSION: &str = - "epiphany.cultmesh.semantic_projection_health.v0"; - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.cultmesh.semantic_projection_health", - schema = "EpiphanyCultMeshSemanticProjectionHealthEntry" -)] -pub struct EpiphanyCultMeshSemanticProjectionHealthEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub verse_id: String, - #[cultcache(key = 2)] - pub verse_tier: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub partition: String, - #[cultcache(key = 5)] - pub obligation_id: String, - #[cultcache(key = 6)] - pub source_generation: u64, - #[cultcache(key = 7)] - pub canonical_model_hash: String, - #[cultcache(key = 8)] - pub canonical_content_set_hash: String, - #[cultcache(key = 9)] - pub status: String, - #[cultcache(key = 10)] - pub receipt_id: Option, - #[cultcache(key = 11)] - pub indexed_document_count: Option, - #[cultcache(key = 12)] - pub vector_dimensions: Option, - #[cultcache(key = 13)] - pub observed_at: String, - #[cultcache(key = 14)] - pub private_state_exposed: bool, - #[cultcache(key = 15)] - pub provider_id: String, - #[cultcache(key = 16)] - pub provider_incarnation: String, - #[cultcache(key = 17)] - pub observed_source_at: String, - #[cultcache(key = 18)] - pub authoritative: bool, - #[cultcache(key = 19)] - pub query_eligible_display_only: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.cultmesh.daemon_heartbeat_event", - schema = "EpiphanyCultMeshDaemonHeartbeatEventEntry" -)] -pub struct EpiphanyCultMeshDaemonHeartbeatEventEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub heartbeat_id: String, - #[cultcache(key = 2)] - pub daemon_id: String, - #[cultcache(key = 3)] - pub cluster_id: String, - #[cultcache(key = 4)] - pub provider_incarnation: String, - #[cultcache(key = 5)] - pub sequence: u64, - #[cultcache(key = 6)] - pub status: String, - #[cultcache(key = 7)] - pub heartbeat_at: String, - #[cultcache(key = 8)] - pub private_state_exposed: bool, - #[cultcache(key = 9, default)] - pub startup_lifecycle_receipt_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.cultmesh.daemon_service_lifecycle_receipt", - schema = "EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry" -)] -pub struct EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub receipt_id: String, - #[cultcache(key = 2)] - pub service_id: String, - #[cultcache(key = 3)] - pub scheduler_id: String, - #[cultcache(key = 4)] - pub runtime_id: String, - #[cultcache(key = 5)] - pub daemon_selector: String, - #[cultcache(key = 6)] - pub action: String, - #[cultcache(key = 7)] - pub status: String, - #[cultcache(key = 8)] - pub command: String, - #[cultcache(key = 9)] - pub args: Vec, - #[cultcache(key = 10)] - pub cwd: Option, - #[cultcache(key = 11)] - pub process_id: Option, - #[cultcache(key = 12)] - pub exit_code: Option, - #[cultcache(key = 13)] - pub started_at_utc: String, - #[cultcache(key = 14)] - pub completed_at_utc: Option, - #[cultcache(key = 15)] - pub operator_artifact_ref: String, - #[cultcache(key = 16)] - pub private_state_exposed: bool, - #[cultcache(key = 17)] - pub notes: Vec, - #[cultcache(key = 18, default)] - pub executable_sha256: String, - #[cultcache(key = 19, default)] - pub preflight_witness_id: String, - #[cultcache(key = 20, default)] - pub required_document_types: Vec, - #[cultcache(key = 21, default)] - pub schema_preflight_passed: bool, - #[cultcache(key = 22, default)] - pub schema_catalog_sha256: String, - #[cultcache(key = 23, default)] - pub managed_policy_id: String, - #[cultcache(key = 24, default)] - pub managed_policy_digest: String, - #[cultcache(key = 25, default)] - pub provider_daemon_id: String, - #[cultcache(key = 26, default)] - pub startup_correlation_id: String, - #[cultcache(key = 27, default)] - pub process_creation_token: u64, - #[cultcache(key = 28, default)] - pub process_created_at_rfc3339: Option, - #[cultcache(key = 29, default)] - pub process_executable_path: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.cultmesh.managed_service_policy", - schema = "EpiphanyCultMeshManagedServicePolicyEntry" -)] -pub struct EpiphanyCultMeshManagedServicePolicyEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub policy_id: String, - #[cultcache(key = 2)] - pub service_id: String, - #[cultcache(key = 4)] - pub command: String, - #[cultcache(key = 5)] - pub args: Vec, - #[cultcache(key = 6)] - pub cwd: Option, - #[cultcache(key = 7)] - pub enabled: bool, - #[cultcache(key = 9)] - pub cooldown_seconds: i64, - #[cultcache(key = 11)] - pub stdout_artifact: String, - #[cultcache(key = 12)] - pub stderr_artifact: String, - #[cultcache(key = 15)] - pub private_state_exposed: bool, -} +pub const EPIPHANY_CANONICAL_SWARM_BRAKE_ID: &str = "epiphany/swarm-brake"; +pub const EPIPHANY_CANONICAL_SWARM_BRAKE_OWNER: &str = "epiphany.swarm-brake"; #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache( @@ -269,23 +46,10 @@ pub struct EpiphanyCultMeshSwarmBrakeEntry { } cultmesh_documents!(EpiphanyCultMeshDocuments { - EpiphanyCultMeshDaemonHeartbeatEventEntry => EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION, - EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry => EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION, - EpiphanyCultMeshManagedServicePolicyEntry => EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION, - WorkspaceCoverageManagedProcessLaunchEntry => WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION, - WorkspaceCoverageProcessEvidenceHead => WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION, - WorkspaceCoverageProviderHeartbeatEntry => WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION, - WorkspaceCoverageProcessTerminationObservationEntry => WORKSPACE_COVERAGE_PROCESS_TERMINATION_SCHEMA_VERSION, - WorkspaceCoverageProjectionProgressEntry => WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION, - WorkspaceCoverageAdvancementSightEntry => WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION, - WorkspaceCoverageClaimSightEntry => WORKSPACE_COVERAGE_CLAIM_SIGHT_SCHEMA_VERSION, - WorkspaceCoverageRecoveryDirectiveEntry => WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_SCHEMA_VERSION, - WorkspaceCoverageTerminalSightEntry => WORKSPACE_COVERAGE_TERMINAL_SIGHT_SCHEMA_VERSION, EpiphanyPackagedReleaseEntry => crate::packaged_release::EPIPHANY_PACKAGED_RELEASE_SCHEMA_VERSION, EpiphanyPackagedReleaseHead => crate::packaged_release::EPIPHANY_PACKAGED_RELEASE_HEAD_SCHEMA_VERSION, EpiphanyCultMeshSwarmBrakeEntry => EPIPHANY_CULTMESH_SWARM_BRAKE_SCHEMA_VERSION, crate::persona_feedback_admission::LocalAdmittedPersonaFeedback => crate::persona_feedback_admission::LOCAL_PERSONA_FEEDBACK_SCHEMA_VERSION, - EpiphanyCultMeshSemanticProjectionHealthEntry => EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_SCHEMA_VERSION, }); pub fn open_epiphany_cultmesh_node( @@ -302,398 +66,16 @@ pub fn open_epiphany_cultmesh_node( ) } -fn semantic_projection_health_scope_key(swarm_id: &str, partition: &str) -> String { - use sha2::{Digest, Sha256}; - format!( - "gamecult-local/semantic-projection-health/{:x}", - Sha256::digest(format!("{swarm_id}|{partition}").as_bytes()) - ) -} - -/// Publishes operator sight derived from authenticated canonical projection state. -/// -/// This mirror is deliberately powerless: it neither creates work nor participates -/// in semantic-query admission. Callers must retain the canonical source store and -/// sealed input for either operation. -pub fn publish_epiphany_cultmesh_semantic_projection_health( - verse_store: impl AsRef, - runtime_id: impl Into, - canonical_store: impl AsRef, - input: &crate::MemorySemanticProjectionInput, - provider_incarnation: &str, -) -> Result { - let runtime_id = runtime_id.into(); - if !bounded_opaque_health_id(&runtime_id) || !bounded_opaque_health_id(provider_incarnation) { - return Err(anyhow!( - "semantic projection health provider identity is required" - )); - } - let observation = crate::observe_memory_semantic_projection(canonical_store, input)?; - let keyed_modeling_basis = input.obligation().partition == "modeling" - && input.obligation().source_commit_id.starts_with("sha256:"); - let entry = EpiphanyCultMeshSemanticProjectionHealthEntry { - schema_version: EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_SCHEMA_VERSION.to_string(), - verse_id: EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID.to_string(), - verse_tier: EPIPHANY_CULTMESH_LOCAL_AREA_TIER.to_string(), - swarm_id: observation.swarm_id, - partition: observation.partition, - obligation_id: observation.obligation_id, - source_generation: observation.source_generation, - canonical_model_hash: observation.canonical_model_hash, - canonical_content_set_hash: observation.canonical_content_set_hash, - status: observation.status, - receipt_id: observation.receipt_id, - indexed_document_count: observation.indexed_document_count, - vector_dimensions: observation.vector_dimensions, - observed_at: Utc::now().to_rfc3339(), - private_state_exposed: false, - provider_id: runtime_id.clone(), - provider_incarnation: provider_incarnation.to_string(), - observed_source_at: observation.observed_source_at, - authoritative: false, - query_eligible_display_only: observation.query_eligible_display_only, - }; - validate_semantic_projection_health(&entry)?; - - let scope_key = semantic_projection_health_scope_key(&entry.swarm_id, &entry.partition); - let latest_key = format!("{scope_key}/latest"); - use sha2::{Digest, Sha256}; - let event_key = format!( - "{scope_key}/event-{:x}", - Sha256::digest( - format!( - "{}|{}|{}|{}", - entry.obligation_id, - entry.status, - entry.receipt_id.as_deref().unwrap_or("none"), - entry.observed_at - ) - .as_bytes() - ) - ); - let node = open_epiphany_cultmesh_node(&verse_store, runtime_id)?; - let backing = SingleFileMessagePackBackingStore::new(verse_store.as_ref()); - for _ in 0..8 { - let opening = backing.pull_all()?; - let latest_envelope = opening.iter().find(|row| { - row.r#type == EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_TYPE && row.key == latest_key - }); - let latest = latest_envelope - .map(|row| { - rmp_serde::from_slice::(&row.payload) - }) - .transpose()?; - if let Some(latest) = &latest { - validate_semantic_projection_health(latest)?; - if !keyed_modeling_basis { - if latest.source_generation == entry.source_generation - && latest.obligation_id != entry.obligation_id - { - return Err(anyhow!( - "semantic projection health generation has conflicting canonical obligations" - )); - } - if latest.source_generation > entry.source_generation { - return Ok(latest.clone()); - } - } - } - let event = node.cache().prepare_entry(&event_key, &entry)?.0; - let latest_replacement = node.cache().prepare_entry(&latest_key, &entry)?.0; - let expected = latest_envelope.cloned().into_iter().collect::>(); - if backing.compare_and_swap_batch(&expected, vec![event, latest_replacement])? { - return Ok(entry); - } - } - Err(anyhow!( - "semantic projection health latest advanced during publication" - )) -} - -pub fn load_epiphany_cultmesh_semantic_projection_health( - verse_store: impl AsRef, - runtime_id: impl Into, -) -> Result> { - let node = open_epiphany_cultmesh_node(verse_store, runtime_id)?; - let mut rows = node - .get_all_with_keys::()? - .into_iter() - .filter(|(key, _)| key.ends_with("/latest")) - .map(|(key, row)| { - let expected_key = format!( - "{}/latest", - semantic_projection_health_scope_key(&row.swarm_id, &row.partition) - ); - if key != expected_key { - return Err(anyhow!( - "semantic projection health latest key does not match its declared scope" - )); - } - Ok(row) - }) - .collect::>>()?; - for row in &rows { - validate_semantic_projection_health(row)?; - } - rows.sort_by(|left, right| { - left.swarm_id - .cmp(&right.swarm_id) - .then(left.partition.cmp(&right.partition)) - }); - Ok(rows) -} - -fn validate_semantic_projection_health( - row: &EpiphanyCultMeshSemanticProjectionHealthEntry, -) -> Result<()> { - if row.schema_version != EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_SCHEMA_VERSION - || row.verse_id != EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID - || row.verse_tier != EPIPHANY_CULTMESH_LOCAL_AREA_TIER - || row.swarm_id.trim().is_empty() - || row.partition != "modeling" - || row.obligation_id.trim().is_empty() - || row.canonical_model_hash.trim().is_empty() - || row.canonical_content_set_hash.trim().is_empty() - || !matches!(row.status.as_str(), "pending" | "failed" | "ready") - || DateTime::parse_from_rfc3339(&row.observed_at).is_err() - || DateTime::parse_from_rfc3339(&row.observed_source_at).is_err() - || row.private_state_exposed - || !bounded_opaque_health_id(&row.provider_id) - || !bounded_opaque_health_id(&row.provider_incarnation) - || row.authoritative - { - return Err(anyhow!("semantic projection health mirror is invalid")); - } - let has_receipt = row.receipt_id.is_some() - && row.indexed_document_count.is_some() - && row.vector_dimensions.is_some(); - if (row.query_eligible_display_only && row.status != "ready") - || has_receipt != (row.status == "ready") - { - return Err(anyhow!( - "semantic projection health evidence shape is invalid" - )); - } - Ok(()) -} - -fn bounded_opaque_health_id(value: &str) -> bool { - !value.is_empty() - && value.len() <= 128 - && value - .bytes() - .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-' | b':')) -} - -pub fn write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - store_path: impl AsRef, - runtime_id: impl Into, - receipt: EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, -) -> Result { - validate_daemon_service_lifecycle_receipt(&receipt)?; - let store_path = store_path.as_ref(); - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let receipt_key = epiphany_cultmesh_daemon_service_lifecycle_receipt_key(&receipt.receipt_id); - if let Some(existing) = - node.get::(&receipt_key)? - { - if existing == receipt { - return Ok(existing); - } - return Err(anyhow!( - "daemon service lifecycle receipt identity collision for {:?}", - receipt.receipt_id - )); - } - let (receipt_envelope, written) = node.cache().prepare_entry(receipt_key, &receipt)?; - let mut expected = Vec::new(); - let mut replacements = vec![receipt_envelope]; - if written.service_id == EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID && written.action == "launch" { - let reserved_name = "semantic projector"; - let policy_key = epiphany_cultmesh_managed_service_policy_key(&written.service_id); - let policy_envelope = node - .cache() - .get_envelope::(&policy_key)? - .ok_or_else(|| anyhow!("reserved {reserved_name} managed policy is absent"))?; - let mut digest = Sha256::new(); - digest.update(policy_envelope.r#type.as_bytes()); - digest.update([0]); - digest.update(policy_envelope.key.as_bytes()); - digest.update([0]); - digest.update(&policy_envelope.payload); - if written.managed_policy_digest != format!("sha256-{:x}", digest.finalize()) { - return Err(anyhow!( - "reserved {reserved_name} launch receipt has stale managed policy digest" - )); - } - expected.push(policy_envelope.clone()); - replacements.push(policy_envelope); - } - let service_current_key = - epiphany_cultmesh_daemon_service_lifecycle_receipt_current_key(&written.service_id); - if let Some(envelope) = node - .cache() - .get_envelope::(&service_current_key)? - { - expected.push(envelope); - } - replacements.push(node.cache().prepare_entry(&service_current_key, &written)?.0); - let backing = SingleFileMessagePackBackingStore::new(store_path); - if backing.compare_and_swap_batch(&expected, replacements)? { - return Ok(written); - } - let reloaded = open_epiphany_cultmesh_node(store_path, "lifecycle-cas-readback")?; - match reloaded.get::( - &epiphany_cultmesh_daemon_service_lifecycle_receipt_key(&written.receipt_id), - )? { - Some(existing) if existing == written => Ok(existing), - Some(_) => Err(anyhow!( - "daemon service lifecycle receipt identity collision for {:?}", - written.receipt_id - )), - None => Err(anyhow!( - "daemon service lifecycle receipt CAS lost concurrent current-state race" - )), - } -} - -pub fn load_epiphany_cultmesh_daemon_service_lifecycle_receipt( - store_path: impl AsRef, - runtime_id: impl Into, - receipt_id: &str, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - node.get(&epiphany_cultmesh_daemon_service_lifecycle_receipt_key( - receipt_id, - )) -} - -pub fn load_epiphany_cultmesh_managed_service_policy_with_digest( - store_path: impl AsRef, - runtime_id: impl Into, - service_id: &str, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let key = epiphany_cultmesh_managed_service_policy_key(service_id); - let Some(policy) = node.get::(&key)? else { - return Ok(None); - }; - validate_managed_service_policy(&policy)?; - let digest = - cultmesh_envelope_digest::(&node, &key)?; - Ok(Some((policy, digest))) -} - -pub fn authenticate_epiphany_cultmesh_semantic_projector_launch( - store_path: impl AsRef, - runtime_id: impl Into, - receipt_id: &str, -) -> Result { - let runtime_id = runtime_id.into(); - let receipt = load_epiphany_cultmesh_daemon_service_lifecycle_receipt( - store_path.as_ref(), - runtime_id.clone(), - receipt_id, - )? - .ok_or_else(|| anyhow!("semantic projector startup launch receipt is absent"))?; - validate_semantic_projector_launch_receipt(&receipt)?; - let (policy, digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( - store_path, - runtime_id, - EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID, - )? - .ok_or_else(|| anyhow!("semantic projector managed policy is absent"))?; - validate_semantic_projector_managed_service_policy(&policy)?; - if receipt.managed_policy_id != policy.policy_id - || receipt.managed_policy_digest != digest - || receipt.command != policy.command - || receipt.args != policy.args - || receipt.cwd != policy.cwd - { - return Err(anyhow!( - "semantic projector startup launch receipt disagrees with current managed policy" - )); - } - Ok(receipt) -} - -pub fn load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( - store_path: impl AsRef, - runtime_id: impl Into, - service_id: &str, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - node.get(&epiphany_cultmesh_daemon_service_lifecycle_receipt_current_key(service_id)) -} - -pub fn write_epiphany_cultmesh_semantic_projector_service_policy( - store_path: impl AsRef, - runtime_id: impl Into, - policy: EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result { - validate_managed_service_policy(&policy)?; - if policy.service_id != EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID { - return Err(anyhow!( - "semantic projector policy writer requires its reserved service id" - )); - } - write_validated_managed_service_policy(store_path, runtime_id, policy) -} - -pub fn write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - store_path: impl AsRef, - runtime_id: impl Into, - policy: EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result { - validate_managed_service_policy(&policy)?; - if policy.service_id != EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID { - return Err(anyhow!( - "workspace coverage projector policy writer requires its reserved service id" - )); - } - write_validated_managed_service_policy(store_path, runtime_id, policy) -} - -fn write_validated_managed_service_policy( - store_path: impl AsRef, - runtime_id: impl Into, - policy: EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result { - let mut node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let key = epiphany_cultmesh_managed_service_policy_key(&policy.service_id); - let written = node.put(key.as_str(), &policy)?; - node.flush()?; - Ok(written) -} - -pub fn load_epiphany_cultmesh_managed_service_policy( - store_path: impl AsRef, - runtime_id: impl Into, - service_id: &str, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let policy = node.get(&epiphany_cultmesh_managed_service_policy_key(service_id))?; - policy - .map(|policy| { - validate_managed_service_policy(&policy)?; - Ok(policy) - }) - .transpose() -} - -pub fn load_epiphany_cultmesh_managed_service_policies( - store_path: impl AsRef, - runtime_id: impl Into, -) -> Result> { - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - node - .get_all_with_keys::()? - .into_iter() - .map(|(_, policy)| { - validate_managed_service_policy(&policy)?; - Ok(policy) - }) - .collect() +pub fn canonical_epiphany_swarm_brake_protected_surfaces() -> Vec { + vec![ + "resident.self".to_string(), + "coordinator.run".to_string(), + "persona.public_speech".to_string(), + "hands.consequence".to_string(), + "atlas.publish".to_string(), + "atlas.project".to_string(), + "atlas.impact_ingress".to_string(), + ] } pub fn default_epiphany_cultmesh_swarm_brake( @@ -704,50 +86,19 @@ pub fn default_epiphany_cultmesh_swarm_brake( brake_id: EPIPHANY_CANONICAL_SWARM_BRAKE_ID.to_string(), status: "released".to_string(), scope: "swarm".to_string(), - reason: "No swarm brake is engaged; unattended automation still requires typed scheduler, cooldown, recovery, and operator receipt gates.".to_string(), + reason: "No swarm brake is engaged; unattended cognition still requires typed authority." + .to_string(), operator_agent_id: EPIPHANY_CANONICAL_SWARM_BRAKE_OWNER.to_string(), affected_clusters: Vec::new(), - protected_surfaces: vec![ - "heartbeat.scheduler".to_string(), - "coordinator.run".to_string(), - "persona.public_speech".to_string(), - "daemon.tool_invocation".to_string(), - "daemon.lifecycle_poke".to_string(), - "atlas.publish".to_string(), - "atlas.project".to_string(), - "atlas.impact_ingress".to_string(), - ], + protected_surfaces: canonical_epiphany_swarm_brake_protected_surfaces(), created_at_utc: generated_at_utc.into(), expires_at_utc: None, private_state_exposed: false, - notes: vec![ - "The swarm brake is the operator-safe pause surface for live-fire readiness.".to_string(), - "It may stop scheduling and daemon pokes, but it must not expose worker thoughts or private Verse state.".to_string(), - "Engaged brakes require a scoped reason so silence cannot masquerade as consent.".to_string(), - ], + notes: vec!["The swarm brake pauses Epiphany cognition and authored consequences.".into()], runtime_id: String::new(), } } -/// The single runtime brake identity shared by deployment, resident readiness, -/// and local typed control surfaces. A caller identity is provenance, not -/// brake ownership, and must not be substituted into either constant. -pub const EPIPHANY_CANONICAL_SWARM_BRAKE_ID: &str = "epiphany/swarm-brake"; -pub const EPIPHANY_CANONICAL_SWARM_BRAKE_OWNER: &str = "epiphany.swarm-brake"; - -pub fn canonical_epiphany_swarm_brake_protected_surfaces() -> Vec { - vec![ - "heartbeat.scheduler".to_string(), - "coordinator.run".to_string(), - "persona.public_speech".to_string(), - "daemon.tool_invocation".to_string(), - "daemon.lifecycle_poke".to_string(), - "atlas.publish".to_string(), - "atlas.project".to_string(), - "atlas.impact_ingress".to_string(), - ] -} - pub fn engage_epiphany_cultmesh_swarm_brake( store_path: impl AsRef, runtime_id: impl Into, @@ -762,9 +113,7 @@ pub fn engage_epiphany_cultmesh_swarm_brake( return Err(anyhow!("swarm brake engagement requires an actor identity")); } if allow_engaged_adoption && actor_id != "Idunn" { - return Err(anyhow!( - "only Idunn may adopt an already-engaged legacy brake" - )); + return Err(anyhow!("only Idunn may adopt an already-engaged legacy brake")); } if let Some(current) = load_epiphany_cultmesh_swarm_brake(&store_path, runtime_id.clone())? { let foreign = current.brake_id != EPIPHANY_CANONICAL_SWARM_BRAKE_ID @@ -782,7 +131,6 @@ pub fn engage_epiphany_cultmesh_swarm_brake( brake.scope = "all".to_string(); brake.reason = reason.into(); brake.affected_clusters = vec![runtime_id.clone()]; - brake.protected_surfaces = canonical_epiphany_swarm_brake_protected_surfaces(); brake.notes = vec![format!("Explicit brake engagement by {actor_id}.")]; write_epiphany_cultmesh_swarm_brake(store_path, runtime_id, brake) } @@ -847,525 +195,22 @@ fn validate_swarm_brake(brake: &EpiphanyCultMeshSwarmBrakeEntry) -> Result<()> { if brake.private_state_exposed { return Err(anyhow!("swarm brake must not expose private state")); } - if brake.brake_id.trim().is_empty() || brake.scope.trim().is_empty() { - return Err(anyhow!("swarm brake requires brake id and scope")); - } - if brake.runtime_id.trim().is_empty() { - return Err(anyhow!("swarm brake requires its owning runtime id")); - } - if brake.created_at_utc.trim().is_empty() { - return Err(anyhow!("swarm brake requires a creation timestamp")); + if brake.brake_id.trim().is_empty() + || brake.scope.trim().is_empty() + || brake.runtime_id.trim().is_empty() + || brake.created_at_utc.trim().is_empty() + { + return Err(anyhow!("swarm brake identity, scope, runtime, and timestamp are required")); } if !matches!(brake.status.as_str(), "released" | "engaged") { return Err(anyhow!("swarm brake status must be released or engaged")); } - if brake.status == "engaged" { - if brake.reason.trim().is_empty() || brake.operator_agent_id.trim().is_empty() { - return Err(anyhow!( - "engaged swarm brake requires operator id and reason" - )); - } - if brake.affected_clusters.is_empty() && brake.protected_surfaces.is_empty() { - return Err(anyhow!( - "engaged swarm brake requires affected clusters or protected surfaces" - )); - } - } - Ok(()) -} - -fn validate_managed_service_policy( - policy: &EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result<()> { - if policy.schema_version != EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION { - return Err(anyhow!("historical managed service policy schema is not writable")); - } - if policy.private_state_exposed { - return Err(anyhow!( - "managed service policies must not expose private state" - )); - } - for (label, value) in [ - ("policy id", policy.policy_id.as_str()), - ("service id", policy.service_id.as_str()), - ("command", policy.command.as_str()), - ("stdout artifact", policy.stdout_artifact.as_str()), - ("stderr artifact", policy.stderr_artifact.as_str()), - ] { - if value.trim().is_empty() { - return Err(anyhow!("managed service policy missing {label}")); - } - } - if policy.cooldown_seconds < 0 { - return Err(anyhow!( - "managed service policy requires a non-negative cooldown" - )); - } - match policy.service_id.as_str() { - EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID => { - validate_semantic_projector_managed_service_policy(policy) - } - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID => { - validate_workspace_coverage_projector_managed_service_policy(policy) - } - _ => Err(anyhow!("unregistered managed service policy is not writable")), - } -} - -fn validate_semantic_projector_managed_service_policy( - policy: &EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result<()> { - let expected_binary = if cfg!(windows) { - "epiphany-memory-semantic-projector.exe" - } else { - "epiphany-memory-semantic-projector" - }; - if Path::new(&policy.command) - .file_name() - .and_then(|name| name.to_str()) - != Some(expected_binary) + if brake.status == "engaged" + && (brake.reason.trim().is_empty() + || brake.operator_agent_id.trim().is_empty() + || (brake.affected_clusters.is_empty() && brake.protected_surfaces.is_empty())) { - return Err(anyhow!( - "reserved semantic projector policy requires the packaged projector executable" - )); - } - if policy.policy_id != "managed-service-policy-epiphany-memory-semantic-projector-service" - || policy.args.len() != 15 - || policy.args[0] != "serve" - || policy.args[1] != "--runtime-store" - || policy.args[2].trim().is_empty() - || policy.args[3] != "--local-verse-store" - || policy.args[4].trim().is_empty() - || policy.args[5] != "--runtime-id" - || policy.args[6].trim().is_empty() - || policy.args[7] != "--interval-seconds" - || policy.args[8].trim().is_empty() - || policy.args[8] - .parse::() - .ok() - .filter(|value| *value > 0) - .is_none() - || policy.args[9] != "--qdrant-url" - || policy.args[10].trim().is_empty() - || policy.args[11] != "--ollama-base-url" - || policy.args[12].trim().is_empty() - || policy.args[13] != "--ollama-model" - || policy.args[14].trim().is_empty() - { - return Err(anyhow!( - "reserved semantic projector policy must bind one packaged process to the canonical Modeling store" - )); - } - Ok(()) -} - -pub(crate) fn validate_workspace_coverage_projector_managed_service_policy( - policy: &EpiphanyCultMeshManagedServicePolicyEntry, -) -> Result<()> { - let expected_binary = if cfg!(windows) { - "epiphany-workspace-coverage-projector.exe" - } else { - "epiphany-workspace-coverage-projector" - }; - let expected_command = std::env::current_exe() - .context("cannot resolve current executable for packaged projector policy")? - .with_file_name(expected_binary); - if Path::new(&policy.command) != expected_command { - return Err(anyhow!( - "reserved workspace coverage projector policy requires the packaged projector executable" - )); - } - if policy.policy_id != "managed-service-policy-epiphany-workspace-coverage-projector-service" - || policy.service_id != EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID - || !policy.enabled - || policy.args.len() != 17 - || policy.args[0] != "serve" - || policy.args[1] != "--runtime-store" - || policy.args[2].trim().is_empty() - || policy.args[3] != "--local-verse-store" - || policy.args[4].trim().is_empty() - || policy.args[5] != "--runtime-id" - || policy.args[6].trim().is_empty() - || policy.args[7] != "--interval-seconds" - || policy.args[8] - .parse::() - .ok() - .filter(|value| *value > 0) - .is_none() - || policy.args[9] != "--heartbeat-interval-seconds" - || policy.args[10] - .parse::() - .ok() - .filter(|value| *value > 0) - .is_none() - || policy.args[11] != "--qdrant-url" - || policy.args[12].trim().is_empty() - || policy.args[13] != "--ollama-base-url" - || policy.args[14].trim().is_empty() - || policy.args[15] != "--ollama-model" - || policy.args[16].trim().is_empty() - { - return Err(anyhow!( - "reserved workspace coverage projector policy must bind one packaged process to its authenticated runtime Body route" - )); - } - Ok(()) -} - -fn validate_daemon_service_lifecycle_receipt( - receipt: &EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, -) -> Result<()> { - if receipt.service_id == EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID { - return Err(anyhow!( - "workspace coverage process authority belongs to its specialized managed process documents" - )); - } - if receipt.private_state_exposed { - return Err(anyhow!( - "daemon service lifecycle receipts must not expose private state" - )); - } - for (label, value) in [ - ("receipt id", receipt.receipt_id.as_str()), - ("service id", receipt.service_id.as_str()), - ("scheduler id", receipt.scheduler_id.as_str()), - ("runtime id", receipt.runtime_id.as_str()), - ("daemon selector", receipt.daemon_selector.as_str()), - ("action", receipt.action.as_str()), - ("status", receipt.status.as_str()), - ("command", receipt.command.as_str()), - ("started at", receipt.started_at_utc.as_str()), - ( - "operator artifact ref", - receipt.operator_artifact_ref.as_str(), - ), - ] { - if value.trim().is_empty() { - return Err(anyhow!("daemon service lifecycle receipt missing {label}")); - } - } - let started_at = DateTime::parse_from_rfc3339(&receipt.started_at_utc).map_err(|error| { - anyhow!("daemon service lifecycle receipt has invalid started at: {error}") - })?; - if let Some(completed_at) = receipt.completed_at_utc.as_deref() { - let completed_at = DateTime::parse_from_rfc3339(completed_at).map_err(|error| { - anyhow!("daemon service lifecycle receipt has invalid completed at: {error}") - })?; - if completed_at < started_at { - return Err(anyhow!( - "daemon service lifecycle receipt completed before it started" - )); - } - } - if !receipt.required_document_types.is_empty() - && (!receipt.schema_preflight_passed - || receipt.executable_sha256.trim().is_empty() - || receipt.schema_catalog_sha256.trim().is_empty() - || receipt.preflight_witness_id.trim().is_empty()) - { - return Err(anyhow!( - "typed daemon service lifecycle receipt requires passing schema preflight, executable fingerprint, and preflight witness" - )); - } - if receipt.service_id == EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID && receipt.action == "launch" { - validate_semantic_projector_launch_receipt(receipt)?; - } - Ok(()) -} - -fn validate_semantic_projector_launch_receipt( - receipt: &EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, -) -> Result<()> { - if receipt.schema_version != EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - || receipt.service_id != EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID - || receipt.action != "launch" - || receipt.status != "launched" - || receipt.process_id.is_none() - || receipt.process_creation_token == 0 - || receipt.process_executable_path.trim().is_empty() - || receipt.exit_code.is_some() - || receipt.completed_at_utc.is_none() - || !receipt.executable_sha256.starts_with("sha256-") - || receipt.managed_policy_id.trim().is_empty() - || !receipt.managed_policy_digest.starts_with("sha256-") - || receipt.provider_daemon_id != "epiphany-memory-semantic-projector" - || receipt.startup_correlation_id != receipt.receipt_id - || Uuid::parse_str(&receipt.receipt_id).is_err() - { - return Err(anyhow!( - "reserved semantic projector launch receipt must bind completed spawn to exact managed policy and provider identity" - )); - } - Ok(()) -} - -fn epiphany_cultmesh_daemon_service_lifecycle_receipt_key(receipt_id: &str) -> String { - format!("epiphany-local/daemon-service-lifecycle-receipt/{receipt_id}") -} - -fn epiphany_cultmesh_daemon_service_lifecycle_receipt_current_key(service_id: &str) -> String { - format!("epiphany-local/daemon-service-lifecycle-receipt/current/{service_id}") -} - -fn epiphany_cultmesh_managed_service_policy_key(service_id: &str) -> String { - format!("epiphany-local/managed-service-policy/{service_id}") -} - -fn epiphany_cultmesh_daemon_heartbeat_event_key(heartbeat_id: &str) -> String { - format!("epiphany-local/daemon-heartbeat/event/{heartbeat_id}") -} - -fn epiphany_cultmesh_daemon_heartbeat_latest_key(daemon_id: &str) -> String { - format!("epiphany-local/daemon-heartbeat/{daemon_id}/latest") -} - -pub fn write_epiphany_cultmesh_daemon_heartbeat_event( - store_path: impl AsRef, - runtime_id: impl Into, - event: EpiphanyCultMeshDaemonHeartbeatEventEntry, -) -> Result { - validate_daemon_heartbeat_event(&event)?; - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - let event_key = epiphany_cultmesh_daemon_heartbeat_event_key(&event.heartbeat_id); - let latest_key = epiphany_cultmesh_daemon_heartbeat_latest_key(&event.daemon_id); - let backing = SingleFileMessagePackBackingStore::new(store_path); - - for _ in 0..8 { - let node = open_epiphany_cultmesh_node(store_path, runtime_id.clone())?; - if let Some(existing) = node.get::(&event_key)? { - return if existing == event { - Ok(existing) - } else { - Err(anyhow!( - "immutable daemon heartbeat identity collision for {:?}", - event.heartbeat_id - )) - }; - } - let latest = node.get::(&latest_key)?; - let advances_latest = match latest.as_ref() { - Some(current) => daemon_heartbeat_advances(current, &event)?, - None => true, - }; - let event_envelope = node.cache().prepare_entry(&event_key, &event)?.0; - let mut replacements = vec![event_envelope]; - let mut expected = Vec::new(); - if advances_latest { - if let Some(envelope) = node - .cache() - .get_envelope::(&latest_key)? - { - expected.push(envelope); - } - replacements.push(node.cache().prepare_entry(&latest_key, &event)?.0); - } - if backing.compare_and_swap_batch(&expected, replacements)? { - return Ok(event); - } - } - Err(anyhow!( - "daemon heartbeat latest advanced during publication" - )) -} - -pub fn load_epiphany_cultmesh_daemon_heartbeat_event( - store_path: impl AsRef, - runtime_id: impl Into, - heartbeat_id: &str, -) -> Result> { - validate_heartbeat_identifier("heartbeat", heartbeat_id)?; - open_epiphany_cultmesh_node(store_path, runtime_id)? - .get(&epiphany_cultmesh_daemon_heartbeat_event_key(heartbeat_id)) -} - -pub fn load_latest_epiphany_cultmesh_daemon_heartbeat( - store_path: impl AsRef, - runtime_id: impl Into, - daemon_id: &str, -) -> Result> { - validate_heartbeat_identifier("daemon", daemon_id)?; - open_epiphany_cultmesh_node(store_path, runtime_id)? - .get(&epiphany_cultmesh_daemon_heartbeat_latest_key(daemon_id)) -} - -#[allow(clippy::too_many_arguments)] -pub fn idunn_recover_memory_semantic_projection_from_cultmesh( - verse_store: impl AsRef, - runtime_id: impl Into, - canonical_store: impl AsRef, - input: &crate::MemorySemanticProjectionInput, - expected_claim_id: &str, - replacement_executor_id: &str, - launch_lifecycle_receipt_id: &str, - provider_heartbeat_id: &str, - recovered_at: &str, -) -> Result<( - crate::MemorySemanticProjectorRecoveryAuthorization, - crate::MemorySemanticProjectionClaim, -)> { - let verse_store = verse_store.as_ref(); - let runtime_id = runtime_id.into(); - let canonical_store = canonical_store.as_ref(); - crate::observe_memory_semantic_projection(canonical_store, input)?; - - let receipt = authenticate_epiphany_cultmesh_semantic_projector_launch( - verse_store, - runtime_id.clone(), - launch_lifecycle_receipt_id, - )?; - let (policy, policy_digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( - verse_store, - runtime_id.clone(), - EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID, - )? - .ok_or_else(|| anyhow!("Idunn recovery managed service policy is absent"))?; - let node = open_epiphany_cultmesh_node(verse_store, runtime_id)?; - let receipt_key = - epiphany_cultmesh_daemon_service_lifecycle_receipt_key(launch_lifecycle_receipt_id); - - let heartbeat_key = epiphany_cultmesh_daemon_heartbeat_event_key(provider_heartbeat_id); - let heartbeat = node - .get::(&heartbeat_key)? - .ok_or_else(|| anyhow!("Idunn recovery provider heartbeat is absent"))?; - validate_daemon_heartbeat_event(&heartbeat)?; - if heartbeat.heartbeat_id != provider_heartbeat_id - || heartbeat.daemon_id != receipt.provider_daemon_id - || heartbeat.cluster_id != "local" - || heartbeat.status != "ready" - || heartbeat.startup_lifecycle_receipt_id != receipt.receipt_id - { - return Err(anyhow!("Idunn recovery provider heartbeat disagrees")); - } - let receipt_completed_at = receipt - .completed_at_utc - .as_deref() - .ok_or_else(|| anyhow!("Idunn recovery launch receipt is not completed"))?; - let receipt_completed = DateTime::parse_from_rfc3339(receipt_completed_at)?; - let heartbeat_at = DateTime::parse_from_rfc3339(&heartbeat.heartbeat_at)?; - if heartbeat_at <= receipt_completed { - return Err(anyhow!( - "Idunn recovery heartbeat must follow lifecycle completion" - )); - } - - let receipt_digest = cultmesh_envelope_digest::< - EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry, - >(&node, &receipt_key)?; - let heartbeat_digest = cultmesh_envelope_digest::( - &node, - &heartbeat_key, - )?; - let evidence = - crate::memory_graph::semantic_projector::idunn_semantic_recovery_evidence_from_cultmesh( - canonical_store, - input, - expected_claim_id, - &format!("idunn-{}", Uuid::new_v4()), - &policy.policy_id, - &policy_digest, - &receipt.receipt_id, - &receipt_digest, - receipt_completed_at, - &heartbeat.heartbeat_id, - &heartbeat_digest, - &heartbeat.provider_incarnation, - &heartbeat.heartbeat_at, - &heartbeat.startup_lifecycle_receipt_id, - )?; - crate::memory_graph::semantic_projector::idunn_recover_memory_semantic_projection( - canonical_store, - input, - expected_claim_id, - replacement_executor_id, - &heartbeat.provider_incarnation, - &evidence, - recovered_at, - ) -} - -fn cultmesh_envelope_digest(node: &CultMeshNode, key: &str) -> Result { - let envelope = node - .cache() - .get_envelope::(key)? - .ok_or_else(|| anyhow!("authenticated CultMesh evidence envelope disappeared"))?; - let mut digest = Sha256::new(); - digest.update(envelope.r#type.as_bytes()); - digest.update([0]); - digest.update(envelope.key.as_bytes()); - digest.update([0]); - digest.update(&envelope.payload); - Ok(format!("sha256-{:x}", digest.finalize())) -} - -fn daemon_heartbeat_advances( - current: &EpiphanyCultMeshDaemonHeartbeatEventEntry, - candidate: &EpiphanyCultMeshDaemonHeartbeatEventEntry, -) -> Result { - validate_daemon_heartbeat_event(current)?; - let current_time = DateTime::parse_from_rfc3339(¤t.heartbeat_at)?; - let candidate_time = DateTime::parse_from_rfc3339(&candidate.heartbeat_at)?; - if current.provider_incarnation == candidate.provider_incarnation { - if candidate.sequence > current.sequence && candidate_time < current_time { - return Err(anyhow!( - "daemon heartbeat time regressed within provider incarnation" - )); - } - if candidate.sequence <= current.sequence { - return Ok(false); - } - } - Ok( - (candidate_time, candidate.sequence, &candidate.heartbeat_id) - > (current_time, current.sequence, ¤t.heartbeat_id), - ) -} - -fn validate_daemon_heartbeat_event( - event: &EpiphanyCultMeshDaemonHeartbeatEventEntry, -) -> Result<()> { - if event.schema_version != EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION { - return Err(anyhow!("unsupported daemon heartbeat schema")); - } - if event.daemon_id == EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID { - return Err(anyhow!( - "workspace coverage provider authority belongs to its specialized signed heartbeat" - )); - } - validate_heartbeat_identifier("heartbeat", &event.heartbeat_id)?; - validate_heartbeat_identifier("daemon", &event.daemon_id)?; - validate_heartbeat_identifier("cluster", &event.cluster_id)?; - validate_heartbeat_identifier("provider incarnation", &event.provider_incarnation)?; - if !event.startup_lifecycle_receipt_id.is_empty() { - validate_heartbeat_identifier( - "startup lifecycle receipt", - &event.startup_lifecycle_receipt_id, - )?; - } - if event.sequence == 0 { - return Err(anyhow!("daemon heartbeat sequence must be positive")); - } - if !matches!(event.status.as_str(), "ready" | "degraded" | "stopping") { - return Err(anyhow!("invalid daemon heartbeat status")); - } - DateTime::parse_from_rfc3339(&event.heartbeat_at) - .context("daemon heartbeat requires RFC3339 heartbeat_at")?; - if event.private_state_exposed { - return Err(anyhow!("daemon heartbeat must not expose private state")); - } - Ok(()) -} - -fn validate_heartbeat_identifier(label: &str, value: &str) -> Result<()> { - if value.is_empty() - || value.len() > 128 - || !value - .bytes() - .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.')) - { - return Err(anyhow!( - "daemon heartbeat requires a bounded opaque {label} id" - )); + return Err(anyhow!("engaged swarm brake requires operator id, reason, and scope")); } Ok(()) } @@ -1373,1096 +218,41 @@ fn validate_heartbeat_identifier(label: &str, value: &str) -> Result<()> { #[cfg(test)] mod tests { use super::*; - use cultcache_rs::CacheBackingStore; - use pretty_assertions::assert_eq; #[test] - fn reserved_semantic_projector_policy_requires_specialized_exact_writer() -> Result<()> { + fn swarm_brake_round_trip_preserves_canonical_authority() -> Result<()> { let temp = tempfile::tempdir()?; - let store = temp.path().join("verse.ccmp"); - let binary = if cfg!(windows) { - "C:\\epiphany-memory-semantic-projector.exe" - } else { - "/tmp/epiphany-memory-semantic-projector" - }; - let exact = EpiphanyCultMeshManagedServicePolicyEntry { - schema_version: EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION.to_string(), - policy_id: "managed-service-policy-epiphany-memory-semantic-projector-service".into(), - service_id: EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID.into(), - command: binary.into(), - args: vec![ - "serve", - "--runtime-store", - "modeling.ccmp", - "--local-verse-store", - "verse.ccmp", - "--runtime-id", - "local", - "--interval-seconds", - "60", - "--qdrant-url", - "http://127.0.0.1:16333", - "--ollama-base-url", - "http://10.77.0.1:11435", - "--ollama-model", - "qwen3-embedding:0.6b", - ] - .into_iter() - .map(str::to_string) - .collect(), - cwd: None, - enabled: true, - cooldown_seconds: 0, - stdout_artifact: "projector.stdout.log".into(), - stderr_artifact: "projector.stderr.log".into(), - private_state_exposed: false, - }; - let historical_store = temp.path().join("historical-verse.ccmp"); - let mut historical = exact.clone(); - historical.schema_version = "epiphany.cultmesh.managed_service_policy.v0".into(); - let mut node = open_epiphany_cultmesh_node(&historical_store, "local")?; - node.put( - epiphany_cultmesh_managed_service_policy_key(&historical.service_id), - &historical, - )?; - node.flush()?; - assert!( - load_epiphany_cultmesh_managed_service_policy( - &historical_store, - "local", - EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID, - ) - .expect_err("historical writable policy must refuse at the load boundary") - .to_string() - .contains("historical managed service policy schema") - ); - let mut forged = exact.clone(); - forged.command = "arbitrary.exe".into(); - assert!( - write_epiphany_cultmesh_semantic_projector_service_policy(&store, "local", forged) - .is_err() - ); - assert!( - write_epiphany_cultmesh_semantic_projector_service_policy( - &store, - "local", - exact.clone(), - ) - .is_ok() - ); - let (_, policy_digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( + let store = temp.path().join("brake.ccmp"); + let engaged = engage_epiphany_cultmesh_swarm_brake( &store, - "local", - EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID, - )? - .context("missing exact policy")?; - let receipt = EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - .into(), - receipt_id: "9f63fa72-a2e1-4ca5-9c1a-9292b7798891".into(), - service_id: EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID.into(), - scheduler_id: "epiphany-daemon-supervisor".into(), - runtime_id: "local".into(), - daemon_selector: "epiphany-daemon-supervisor".into(), - action: "launch".into(), - status: "launched".into(), - command: exact.command.clone(), - args: exact.args.clone(), - cwd: exact.cwd.clone(), - process_id: Some(4242), - exit_code: None, - started_at_utc: "2026-07-15T12:00:00Z".into(), - completed_at_utc: Some("2026-07-15T12:00:01Z".into()), - operator_artifact_ref: "service://semantic-projector/launch".into(), - private_state_exposed: false, - notes: vec![], - executable_sha256: "sha256-test-projector".into(), - preflight_witness_id: String::new(), - required_document_types: vec![], - schema_preflight_passed: false, - schema_catalog_sha256: String::new(), - managed_policy_id: exact.policy_id.clone(), - managed_policy_digest: policy_digest, - provider_daemon_id: "epiphany-memory-semantic-projector".into(), - startup_correlation_id: "9f63fa72-a2e1-4ca5-9c1a-9292b7798891".into(), - process_creation_token: 1, - process_created_at_rfc3339: None, - process_executable_path: "C:\\epiphany\\semantic-projector.exe".into(), - }; - let written = write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "local", - receipt.clone(), - )?; - assert_eq!( - authenticate_epiphany_cultmesh_semantic_projector_launch( - &store, - "local", - &receipt.receipt_id, - )?, - written - ); - assert_eq!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "local", - receipt.clone(), - )?, - receipt - ); - let mut collision = receipt; - collision.process_id = Some(4343); - assert!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt(&store, "local", collision,) - .unwrap_err() - .to_string() - .contains("identity collision") - ); - Ok(()) - } - - #[test] - fn reserved_workspace_coverage_projector_contract_is_exact_and_policy_bound() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("verse.ccmp"); - let binary = std::env::current_exe()?.with_file_name(if cfg!(windows) { - "epiphany-workspace-coverage-projector.exe" - } else { - "epiphany-workspace-coverage-projector" - }); - let exact = EpiphanyCultMeshManagedServicePolicyEntry { - schema_version: EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION.to_string(), - policy_id: "managed-service-policy-epiphany-workspace-coverage-projector-service" - .into(), - service_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID.into(), - command: binary.display().to_string(), - args: vec![ - "serve", - "--runtime-store", - "runtime.ccmp", - "--local-verse-store", - "verse.ccmp", - "--runtime-id", - "local", - "--interval-seconds", - "60", - "--heartbeat-interval-seconds", - "10", - "--qdrant-url", - "http://127.0.0.1:6333", - "--ollama-base-url", - "http://127.0.0.1:11434", - "--ollama-model", - "qwen3-embedding:0.6b", - ] - .into_iter() - .map(str::to_string) - .collect(), - cwd: None, - enabled: true, - cooldown_seconds: 0, - stdout_artifact: "workspace-projector.stdout.log".into(), - stderr_artifact: "workspace-projector.stderr.log".into(), - private_state_exposed: false, - }; - let mut arbitrary_binary = exact.clone(); - arbitrary_binary.command = "arbitrary-projector.exe".into(); - assert!( - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, - "local", - arbitrary_binary, - ) - .is_err() - ); - let mut injected_workspace = exact.clone(); - injected_workspace.args.insert(3, "--workspace".into()); - injected_workspace.args.insert(4, "stolen".into()); - assert!( - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, - "local", - injected_workspace, - ) - .is_err() - ); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, - "local", - exact.clone(), - )?; - let receipt_id = "fd3b7be9-02b0-4ac7-a47e-2d25097ff1f5"; - let receipt = EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - .into(), - receipt_id: receipt_id.into(), - service_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID.into(), - scheduler_id: "epiphany-daemon-supervisor".into(), - runtime_id: "local".into(), - daemon_selector: "epiphany-daemon-supervisor".into(), - action: "launch".into(), - status: "launched".into(), - command: exact.command.clone(), - args: exact.args.clone(), - cwd: exact.cwd.clone(), - process_id: Some(4242), - exit_code: None, - started_at_utc: "2026-07-15T12:00:00Z".into(), - completed_at_utc: Some("2026-07-15T12:00:01Z".into()), - operator_artifact_ref: "service://workspace-coverage-projector/launch".into(), - private_state_exposed: false, - notes: vec![], - executable_sha256: "sha256-test-workspace-projector".into(), - preflight_witness_id: String::new(), - required_document_types: vec![], - schema_preflight_passed: false, - schema_catalog_sha256: String::new(), - managed_policy_id: exact.policy_id.clone(), - managed_policy_digest: "sha256-dead-authority".into(), - provider_daemon_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID.into(), - startup_correlation_id: receipt_id.into(), - process_creation_token: 1, - process_created_at_rfc3339: None, - process_executable_path: "C:\\epiphany\\semantic-projector.exe".into(), - }; - let mut wrong_provider = receipt.clone(); - wrong_provider.receipt_id = "f6d454dd-3765-44cb-930a-bae0d47487aa".into(); - wrong_provider.startup_correlation_id = wrong_provider.receipt_id.clone(); - wrong_provider.provider_daemon_id = "epiphany-memory-semantic-projector".into(); - assert!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "local", - wrong_provider, - ) - .is_err() - ); - let mut stale = receipt.clone(); - stale.receipt_id = "a0ea76d1-9a9a-4dc7-a8bc-a56ab1d8079a".into(); - stale.startup_correlation_id = stale.receipt_id.clone(); - stale.managed_policy_digest = "sha256-stale".into(); - assert!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt(&store, "local", stale) - .is_err() - ); - assert!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "local", - receipt.clone(), - ) - .unwrap_err() - .to_string() - .contains("specialized managed process documents") - ); - - let mut advanced = exact; - advanced.args[8] = "61".into(); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, "local", advanced, - )?; - assert!( - load_epiphany_cultmesh_daemon_service_lifecycle_receipt(&store, "local", receipt_id,)? - .is_none() - ); - let generic_heartbeat = EpiphanyCultMeshDaemonHeartbeatEventEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION.to_string(), - heartbeat_id: Uuid::new_v4().to_string(), - daemon_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID.to_string(), - cluster_id: "local".to_string(), - provider_incarnation: Uuid::new_v4().to_string(), - sequence: 1, - status: "ready".to_string(), - heartbeat_at: "2026-07-15T12:00:03Z".to_string(), - private_state_exposed: false, - startup_lifecycle_receipt_id: receipt_id.to_string(), - }; - assert!( - write_epiphany_cultmesh_daemon_heartbeat_event(&store, "local", generic_heartbeat,) - .unwrap_err() - .to_string() - .contains("specialized signed heartbeat") - ); - Ok(()) - } - - fn semantic_health_input( - store: &Path, - swarm_id: &str, - partition: &str, - generation: u64, - ) -> Result { - let graph_id = format!("{partition}-graph"); - let obligation = crate::MemorySemanticProjectionObligation { - schema_version: crate::MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION.to_string(), - obligation_id: format!("obligation-{partition}-{generation}"), - swarm_id: swarm_id.to_string(), - partition: partition.to_string(), - canonical_source_id: format!("canonical/{partition}"), - source_commit_id: format!("commit-{generation}"), - graph_id: graph_id.clone(), - source_generation: generation, - source_model_hash: format!("model-{generation}"), - canonical_content_set_hash: format!("content-{generation}"), - projection_schema_version: crate::SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - created_at: "2026-07-15T12:00:00Z".to_string(), - }; - let head = crate::MemorySemanticProjectionSourceHead { - swarm_id: swarm_id.to_string(), - partition: partition.to_string(), - canonical_source_id: format!("canonical/{partition}"), - source_commit_id: format!("commit-{generation}"), - graph_id: graph_id.clone(), - source_generation: generation, - source_model_hash: format!("model-{generation}"), - canonical_content_set_hash: format!("content-{generation}"), - }; - let mut cache = crate::memory_graph::semantic_projector::semantic_projector_cache(store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let envelopes = SingleFileMessagePackBackingStore::new(store).pull_all()?; - let authority = envelopes - .into_iter() - .find(|row| { - row.r#type == "gamecult.epiphany.memory_semantic_projection_obligation" - && row.key == obligation.obligation_id - }) - .expect("persisted obligation envelope"); - Ok(crate::MemorySemanticProjectionInput { - snapshot: crate::EpiphanyMemoryGraphSnapshot { - schema_version: Some("v0".to_string()), - graph_id, - model_revision: generation, - ..Default::default() - }, - obligation, - authority: - crate::memory_graph::semantic_projector::MemorySemanticProjectionAuthoritySnapshot { - head, - envelopes: vec![authority], - }, - }) - } - - #[test] - fn semantic_health_publication_is_monotonic_sight_only() -> Result<()> { - let temp = tempfile::tempdir()?; - let canonical = temp.path().join("canonical.msgpack"); - let verse = temp.path().join("verse.ccmp"); - let modeling_1 = semantic_health_input(&canonical, "swarm-a", "modeling", 1)?; - let modeling_2 = semantic_health_input(&canonical, "swarm-a", "modeling", 2)?; - let before = SingleFileMessagePackBackingStore::new(&canonical).pull_all()?; - - publish_epiphany_cultmesh_semantic_projection_health( - &verse, "runtime", - &canonical, - &modeling_1, - "incarnation-a", - )?; - publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &modeling_2, - "incarnation-a", - )?; - let delayed = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &modeling_1, - "incarnation-a", - )?; - assert_eq!(delayed.source_generation, 2); - let rows = load_epiphany_cultmesh_semantic_projection_health(&verse, "runtime")?; - assert_eq!(rows.len(), 1); - assert_eq!(rows[0].partition, "modeling"); - assert_eq!(rows[0].source_generation, 2); - assert!(rows.iter().all(|row| !row.private_state_exposed)); - assert_eq!( - SingleFileMessagePackBackingStore::new(&canonical).pull_all()?, - before, - "publishing sight must not create canonical projection work" - ); - Ok(()) - } - - #[test] - fn semantic_health_rejects_older_conflicting_obligation_for_same_generation() -> Result<()> { - let temp = tempfile::tempdir()?; - let canonical = temp.path().join("canonical.msgpack"); - let verse = temp.path().join("verse.ccmp"); - let mut latest = semantic_health_input(&canonical, "swarm-a", "modeling", 2)?; - latest.obligation.created_at = "2026-07-15T12:02:00Z".to_string(); - let mut cache = - crate::memory_graph::semantic_projector::semantic_projector_cache(&canonical)?; - cache.put(&latest.obligation.obligation_id, &latest.obligation)?; - latest.authority.envelopes = SingleFileMessagePackBackingStore::new(&canonical) - .pull_all()? - .into_iter() - .filter(|row| { - row.r#type == "gamecult.epiphany.memory_semantic_projection_obligation" - && row.key == latest.obligation.obligation_id - }) - .collect(); - publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &latest, - "incarnation-a", - )?; - - let mut older_conflict = latest.clone(); - older_conflict.obligation.obligation_id = "conflicting-obligation-modeling-2".to_string(); - older_conflict.obligation.created_at = "2026-07-15T12:01:00Z".to_string(); - cache.put( - &older_conflict.obligation.obligation_id, - &older_conflict.obligation, - )?; - older_conflict.authority.envelopes = SingleFileMessagePackBackingStore::new(&canonical) - .pull_all()? - .into_iter() - .filter(|row| { - row.r#type == "gamecult.epiphany.memory_semantic_projection_obligation" - && row.key == older_conflict.obligation.obligation_id - }) - .collect(); - - let error = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &older_conflict, - "incarnation-a", - ) - .expect_err("chronology must not hide a same-generation obligation conflict"); - assert!( - error - .to_string() - .contains("conflicting canonical obligations") - ); - Ok(()) - } - - #[test] - fn semantic_health_loader_rejects_latest_outside_declared_scope() -> Result<()> { - let temp = tempfile::tempdir()?; - let canonical = temp.path().join("canonical.msgpack"); - let verse = temp.path().join("verse.ccmp"); - let input = semantic_health_input(&canonical, "swarm-a", "modeling", 1)?; - let row = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &input, - "incarnation-a", - )?; - let hostile_key = format!( - "{}/latest", - semantic_projection_health_scope_key("other-swarm", "modeling") - ); - let mut node = open_epiphany_cultmesh_node(&verse, "hostile")?; - node.put(hostile_key, &row)?; - node.flush()?; - - let error = load_epiphany_cultmesh_semantic_projection_health(&verse, "runtime") - .expect_err("a latest row must authenticate its key scope"); - assert!( - error - .to_string() - .contains("does not match its declared scope") - ); - Ok(()) - } - - #[test] - fn forged_ready_health_cannot_mint_canonical_readiness() -> Result<()> { - let temp = tempfile::tempdir()?; - let canonical = temp.path().join("canonical.msgpack"); - let verse = temp.path().join("verse.ccmp"); - let input = semantic_health_input(&canonical, "swarm-a", "modeling", 1)?; - let mut empty_authority = input.clone(); - empty_authority.authority.envelopes.clear(); - assert!( - publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &empty_authority, - "incarnation-a" - ) - .is_err() - ); - let other_store = temp.path().join("other.msgpack"); - assert!( - publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &other_store, - &input, - "incarnation-a" - ) - .is_err() - ); - let mut forged = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "runtime", - &canonical, - &input, - "incarnation-a", - )?; - forged.status = "ready".to_string(); - forged.receipt_id = Some("forged-receipt".to_string()); - forged.indexed_document_count = Some(999); - forged.vector_dimensions = Some(999); - let mut node = open_epiphany_cultmesh_node(&verse, "hostile")?; - node.put("gamecult-local/hostile/forged-ready", &forged)?; - node.flush()?; - - assert!( - crate::load_memory_semantic_projection_readiness(&canonical, &input)?.is_none(), - "CultMesh mirrors are not an import edge into canonical readiness" - ); - let mut config = crate::MemorySemanticIndexConfig::from_env(); - config.qdrant_url = "http://127.0.0.1:1".to_string(); - let packet = crate::semantic_memory_context( - input.snapshot(), - "swarm-a", - &crate::EpiphanyMemoryContextQuery { - id: "hostile-query".to_string(), - text: Some("test".to_string()), - ..Default::default() - }, - None, - &config, - ); - assert!( - packet - .warnings - .iter() - .any(|warning| warning.contains("canonical BM25")) - ); - Ok(()) - } - - #[test] - fn semantic_health_preserves_projection_states_and_later_repair_failure() -> Result<()> { - let temp = tempfile::tempdir()?; - let canonical = temp.path().join("canonical.msgpack"); - let verse = temp.path().join("verse.ccmp"); - let input = semantic_health_input(&canonical, "swarm-four", "modeling", 7)?; - let pending = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "provider", - &canonical, - &input, - "incarnation-a", - )?; - assert_eq!(pending.status, "pending"); - - let claim = - crate::memory_graph::semantic_projector::idunn_acquire_memory_semantic_projection( - &canonical, - &input, - "executor-a", - "executor-a-incarnation", - "execute", - "idunn-test-incarnation", - "2026-07-15T12:01:00Z", - )? - .claim; - let raw_receipt = crate::MemorySemanticIndexReceipt { - schema_version: crate::MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id: "receipt-four-state".to_string(), - swarm_id: input.obligation().swarm_id.clone(), - partition: input.obligation().partition.clone(), - collection_name: "projection".to_string(), - graph_id: input.obligation().graph_id.clone(), - model_revision: input.obligation().source_generation, - model_hash: input.obligation().source_model_hash.clone(), - embedding_provider_id: "embedder".to_string(), - embedding_model: "model".to_string(), - vector_dimensions: 3, - indexed_document_count: 2, - deleted_document_count: 0, - canonical_content_set_hash: input.obligation().canonical_content_set_hash.clone(), - indexed_at: "2026-07-15T12:02:00Z".to_string(), - status: "ready".to_string(), - obligation_id: claim.obligation_id.clone(), - canonical_source_id: String::new(), - source_commit_id: String::new(), - source_generation: input.obligation().source_generation, - projection_schema_version: crate::SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - claim_id: claim.claim_id.clone(), - claim_epoch: claim.epoch, - observed_vector_binding_root_sha256: "0".repeat(64), - }; - crate::memory_graph::semantic_projector::succeed_memory_semantic_projection_claim( - &canonical, - &claim.claim_id, - &input.authority, - raw_receipt, - "2026-07-15T12:02:01Z", - )?; - let ready = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "provider", - &canonical, - &input, - "incarnation-a", - )?; - assert_eq!(ready.status, "ready"); - assert!(ready.query_eligible_display_only); - let mut empty_ready = ready.clone(); - empty_ready.indexed_document_count = Some(0); - empty_ready.vector_dimensions = Some(0); - empty_ready.query_eligible_display_only = false; - validate_semantic_projection_health(&empty_ready)?; - - let repair = - crate::memory_graph::semantic_projector::idunn_acquire_memory_semantic_projection( - &canonical, - &input, - "executor-b", - "executor-b-incarnation", - "repair", - "idunn-test-incarnation", - "2026-07-15T12:03:00Z", - )? - .claim; - crate::memory_graph::semantic_projector::fail_memory_semantic_projection_claim( - &canonical, - &repair.claim_id, - "2026-07-15T12:04:00Z", - "private backend failure /secret/path", - )?; - let failed = publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "provider", - &canonical, - &input, - "incarnation-a", - )?; - assert_eq!(failed.status, "failed"); - assert!(!failed.query_eligible_display_only); - assert!(failed.receipt_id.is_none()); - let encoded = format!("{failed:?}"); - assert!(!encoded.contains("private backend failure")); - assert!(!encoded.contains("/secret/path")); - - let mut stale_input = input.clone(); - stale_input.authority.head.source_generation += 1; - assert!(crate::observe_memory_semantic_projection(&canonical, &stale_input).is_err()); - assert!( - publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "provider", - &canonical, - &stale_input, - "incarnation-a" - ) - .is_err() - ); - assert!( - publish_epiphany_cultmesh_semantic_projection_health( - &verse, - "provider", - &canonical, - &input, - "C:\\secret\\token" - ) - .is_err() - ); - - Ok(()) - } - - #[test] - fn service_lifecycle_receipt_refuses_invalid_or_reversed_time() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp - .path() - .join("epiphany-service-lifecycle-invalid-time.ccmp"); - let mut receipt = EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - .to_string(), - receipt_id: "service-lifecycle-invalid-time".to_string(), - service_id: "epiphany-daemon-supervisor-service".to_string(), - scheduler_id: "epiphany-daemon-supervisor".to_string(), - runtime_id: "epiphany-test".to_string(), - daemon_selector: "epiphany-daemon-supervisor".to_string(), - action: "windows-service-status".to_string(), - status: "running".to_string(), - command: "powershell.exe".to_string(), - args: Vec::new(), - cwd: None, - process_id: None, - exit_code: Some(0), - started_at_utc: "not-a-time".to_string(), - completed_at_utc: None, - operator_artifact_ref: "test://invalid-time".to_string(), - private_state_exposed: false, - notes: Vec::new(), - executable_sha256: String::new(), - preflight_witness_id: String::new(), - required_document_types: Vec::new(), - schema_preflight_passed: false, - schema_catalog_sha256: String::new(), - managed_policy_id: String::new(), - managed_policy_digest: String::new(), - provider_daemon_id: String::new(), - startup_correlation_id: String::new(), - process_creation_token: 0, - process_created_at_rfc3339: None, - process_executable_path: String::new(), - }; - assert!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test", - receipt.clone(), - ) - .is_err() - ); - receipt.started_at_utc = "2026-07-13T02:00:00Z".to_string(); - receipt.completed_at_utc = Some("2026-07-13T01:00:00Z".to_string()); - assert!( - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &store, - "epiphany-test", - receipt, - ) - .is_err() - ); - assert!( - load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service( - &store, - "epiphany-test", - "epiphany-daemon-supervisor-service", - )? - .is_none() - ); - Ok(()) - } - - #[test] - fn canonical_engagement_protects_daemon_lifecycle_actuation() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("epiphany-canonical-swarm-brake.ccmp"); - let brake = engage_epiphany_cultmesh_swarm_brake( - &store, - "epiphany-test", - "Hold every consequence surface during shakedown.", - "Idunn", - "2026-08-11T00:00:00Z", + "test", + "operator", + "2026-08-23T00:00:00Z", false, )?; - - assert_eq!(brake.status, "engaged"); - assert_eq!(brake.scope, "all"); - assert!( - brake - .protected_surfaces - .iter() - .any(|surface| surface == "daemon.lifecycle_poke") + assert_eq!(engaged.status, "engaged"); + assert_eq!(engaged.brake_id, EPIPHANY_CANONICAL_SWARM_BRAKE_ID); + assert!(engaged.protected_surfaces.iter().any(|value| value == "hands.consequence")); + assert_eq!( + load_epiphany_cultmesh_swarm_brake(&store, "runtime")?, + Some(engaged) ); Ok(()) } #[test] - fn swarm_brake_refuses_private_state_or_unreasoned_engagement() -> Result<()> { + fn swarm_brake_refuses_private_or_unreasoned_engagement() -> Result<()> { let temp = tempfile::tempdir()?; - let store = temp.path().join("epiphany-swarm-brake-refusal.ccmp"); - let mut brake = default_epiphany_cultmesh_swarm_brake("2026-06-17T00:00:00Z"); + let store = temp.path().join("brake.ccmp"); + let mut brake = default_epiphany_cultmesh_swarm_brake("2026-08-23T00:00:00Z"); brake.private_state_exposed = true; - let error = write_epiphany_cultmesh_swarm_brake(&store, "epiphany-test", brake) - .expect_err("private swarm brake must be refused"); - assert!(error.to_string().contains("private state")); + assert!(write_epiphany_cultmesh_swarm_brake(&store, "runtime", brake).is_err()); - let mut brake = default_epiphany_cultmesh_swarm_brake("2026-06-17T00:00:00Z"); - brake.status = "engaged".to_string(); + let mut brake = default_epiphany_cultmesh_swarm_brake("2026-08-23T00:00:00Z"); + brake.status = "engaged".into(); brake.reason.clear(); - let error = write_epiphany_cultmesh_swarm_brake(&store, "epiphany-test", brake) - .expect_err("unreasoned engaged swarm brake must be refused"); - assert!(error.to_string().contains("operator id and reason")); - Ok(()) - } - - fn heartbeat_event( - heartbeat_id: &str, - incarnation: &str, - sequence: u64, - heartbeat_at: &str, - ) -> EpiphanyCultMeshDaemonHeartbeatEventEntry { - EpiphanyCultMeshDaemonHeartbeatEventEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION.to_string(), - heartbeat_id: heartbeat_id.to_string(), - daemon_id: "daemon-test".to_string(), - cluster_id: "cluster-test".to_string(), - provider_incarnation: incarnation.to_string(), - sequence, - status: "ready".to_string(), - heartbeat_at: heartbeat_at.to_string(), - private_state_exposed: false, - startup_lifecycle_receipt_id: String::new(), - } - } - - #[test] - fn daemon_heartbeat_events_are_immutable_and_advance_latest_monotonically() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("daemon-heartbeats.ccmp"); - let first = heartbeat_event("heartbeat-1", "incarnation-a", 1, "2026-07-15T12:00:00Z"); - write_epiphany_cultmesh_daemon_heartbeat_event(&store, "runtime-test", first.clone())?; - assert_eq!( - load_epiphany_cultmesh_daemon_heartbeat_event(&store, "runtime-test", "heartbeat-1")?, - Some(first.clone()) - ); - - let delayed = heartbeat_event( - "heartbeat-delayed", - "incarnation-a", - 1, - "2026-07-15T11:59:59Z", - ); - write_epiphany_cultmesh_daemon_heartbeat_event(&store, "runtime-test", delayed)?; - assert_eq!( - load_latest_epiphany_cultmesh_daemon_heartbeat(&store, "runtime-test", "daemon-test")?, - Some(first.clone()) - ); - - let restarted = heartbeat_event("heartbeat-2", "incarnation-b", 1, "2026-07-15T12:00:01Z"); - write_epiphany_cultmesh_daemon_heartbeat_event(&store, "runtime-test", restarted.clone())?; - assert_eq!( - load_latest_epiphany_cultmesh_daemon_heartbeat(&store, "runtime-test", "daemon-test")?, - Some(restarted) - ); - - let mut collision = first.clone(); - collision.status = "degraded".to_string(); - assert!( - write_epiphany_cultmesh_daemon_heartbeat_event(&store, "runtime-test", collision) - .expect_err("heartbeat identity is immutable") - .to_string() - .contains("identity collision") - ); - let mut private = heartbeat_event( - "heartbeat-private", - "incarnation-b", - 2, - "2026-07-15T12:00:02Z", - ); - private.private_state_exposed = true; - assert!( - write_epiphany_cultmesh_daemon_heartbeat_event(&store, "runtime-test", private) - .expect_err("private heartbeat must be refused") - .to_string() - .contains("must not expose private state") - ); - Ok(()) - } - - #[test] - fn semantic_recovery_requires_current_policy_launch_heartbeat_chain_and_is_single_use() - -> Result<()> { - let temp = tempfile::tempdir()?; - let canonical = temp.path().join("canonical.msgpack"); - let verse = temp.path().join("verse.ccmp"); - let input = semantic_health_input(&canonical, "swarm-recovery", "modeling", 1)?; - let claim = - crate::memory_graph::semantic_projector::idunn_acquire_memory_semantic_projection( - &canonical, - &input, - "executor-old", - "provider-old", - "execute", - "idunn-test-incarnation", - "2026-07-15T12:00:00Z", - )? - .claim; - let binary = if cfg!(windows) { - "C:\\epiphany-memory-semantic-projector.exe" - } else { - "/tmp/epiphany-memory-semantic-projector" - }; - let policy = EpiphanyCultMeshManagedServicePolicyEntry { - schema_version: EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION.to_string(), - policy_id: "managed-service-policy-epiphany-memory-semantic-projector-service".into(), - service_id: EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID.into(), - command: binary.into(), - args: vec![ - "serve", - "--runtime-store", - "modeling.ccmp", - "--local-verse-store", - "verse.ccmp", - "--runtime-id", - "runtime-test", - "--interval-seconds", - "60", - "--qdrant-url", - "http://127.0.0.1:16333", - "--ollama-base-url", - "http://10.77.0.1:11435", - "--ollama-model", - "qwen3-embedding:0.6b", - ] - .into_iter() - .map(str::to_string) - .collect(), - cwd: None, - enabled: true, - cooldown_seconds: 0, - stdout_artifact: "projector.stdout.log".into(), - stderr_artifact: "projector.stderr.log".into(), - private_state_exposed: false, - }; - write_epiphany_cultmesh_semantic_projector_service_policy( - &verse, - "runtime-test", - policy.clone(), - )?; - let (_, policy_digest) = load_epiphany_cultmesh_managed_service_policy_with_digest( - &verse, - "runtime-test", - EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID, - )? - .context("semantic policy missing")?; - let receipt = EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION - .into(), - receipt_id: "f32666a9-94ce-47c5-b2bd-7d18624dfe9b".into(), - service_id: EPIPHANY_SEMANTIC_PROJECTOR_SERVICE_ID.into(), - scheduler_id: "epiphany-daemon-supervisor".into(), - runtime_id: "runtime-test".into(), - daemon_selector: "epiphany-daemon-supervisor".into(), - action: "launch".into(), - status: "launched".into(), - command: policy.command.clone(), - args: policy.args.clone(), - cwd: None, - process_id: Some(4242), - exit_code: None, - started_at_utc: "2026-07-15T12:01:00Z".into(), - completed_at_utc: Some("2026-07-15T12:02:00Z".into()), - operator_artifact_ref: "service://semantic-projector/launch".into(), - private_state_exposed: false, - notes: vec![], - executable_sha256: "sha256-test-projector".into(), - preflight_witness_id: String::new(), - required_document_types: vec![], - schema_preflight_passed: false, - schema_catalog_sha256: String::new(), - managed_policy_id: policy.policy_id.clone(), - managed_policy_digest: policy_digest, - provider_daemon_id: "epiphany-memory-semantic-projector".into(), - startup_correlation_id: "f32666a9-94ce-47c5-b2bd-7d18624dfe9b".into(), - process_creation_token: 1, - process_created_at_rfc3339: None, - process_executable_path: "C:\\epiphany\\semantic-projector.exe".into(), - }; - write_epiphany_cultmesh_daemon_service_lifecycle_receipt( - &verse, - "runtime-test", - receipt.clone(), - )?; - - let unrelated = EpiphanyCultMeshDaemonHeartbeatEventEntry { - schema_version: EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION.to_string(), - heartbeat_id: "semantic-heartbeat-unrelated".to_string(), - daemon_id: "epiphany-memory-semantic-projector".into(), - cluster_id: "local".into(), - provider_incarnation: "provider-new".to_string(), - sequence: 1, - status: "ready".to_string(), - heartbeat_at: "2026-07-15T12:03:00Z".to_string(), - private_state_exposed: false, - startup_lifecycle_receipt_id: String::new(), - }; - write_epiphany_cultmesh_daemon_heartbeat_event(&verse, "runtime-test", unrelated)?; - assert!( - idunn_recover_memory_semantic_projection_from_cultmesh( - &verse, - "runtime-test", - &canonical, - &input, - &claim.claim_id, - "executor-new", - &receipt.receipt_id, - "semantic-heartbeat-unrelated", - "2026-07-15T12:04:00Z", - ) - .is_err() - ); - - let mut advanced_policy = policy.clone(); - advanced_policy.args[8] = "61".into(); - write_epiphany_cultmesh_semantic_projector_service_policy( - &verse, - "runtime-test", - advanced_policy, - )?; - assert!( - idunn_recover_memory_semantic_projection_from_cultmesh( - &verse, - "runtime-test", - &canonical, - &input, - &claim.claim_id, - "executor-new", - &receipt.receipt_id, - "semantic-heartbeat-unrelated", - "2026-07-15T12:04:00Z", - ) - .expect_err("an obsolete launch receipt cannot authorize a newer policy") - .to_string() - .contains("disagrees with current managed policy") - ); - write_epiphany_cultmesh_semantic_projector_service_policy(&verse, "runtime-test", policy)?; - - let correlated = EpiphanyCultMeshDaemonHeartbeatEventEntry { - heartbeat_id: "semantic-heartbeat-correlated".to_string(), - sequence: 2, - startup_lifecycle_receipt_id: receipt.receipt_id.clone(), - ..heartbeat_event( - "semantic-heartbeat-template", - "provider-new", - 2, - "2026-07-15T12:03:00Z", - ) - }; - let mut correlated = correlated; - correlated.daemon_id = "epiphany-memory-semantic-projector".into(); - correlated.cluster_id = "local".into(); - write_epiphany_cultmesh_daemon_heartbeat_event(&verse, "runtime-test", correlated.clone())?; - let (_, recovered) = idunn_recover_memory_semantic_projection_from_cultmesh( - &verse, - "runtime-test", - &canonical, - &input, - &claim.claim_id, - "executor-new", - &receipt.receipt_id, - &correlated.heartbeat_id, - "2026-07-15T12:04:00Z", - )?; - assert_eq!(recovered.epoch, claim.epoch + 1); - assert_eq!(recovered.executor_incarnation, "provider-new"); - assert!( - idunn_recover_memory_semantic_projection_from_cultmesh( - &verse, - "runtime-test", - &canonical, - &input, - &recovered.claim_id, - "executor-third", - &receipt.receipt_id, - &correlated.heartbeat_id, - "2026-07-15T12:05:00Z", - ) - .is_err() - ); + assert!(write_epiphany_cultmesh_swarm_brake(&store, "runtime", brake).is_err()); Ok(()) } } diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index 7525d17f..03413e91 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -28,27 +28,15 @@ mod reorientation_work; mod repo_model_documents; mod repo_model_gateway; mod repository_body_observer; -mod repository_readiness; mod resident_readiness; mod resident_self; mod runtime_spine; mod runtime_store_backend; mod runtime_worker_attempt; -mod semantic_backend; -mod semantic_projector_service; mod soul_gateway; mod state_ledger; mod substrate_gate; mod surfaces; -mod workspace_coverage_process_bootstrap; -mod workspace_coverage_process_documents; -mod workspace_coverage_projection_batch_checkpoint; -mod workspace_coverage_projection_progress; -mod workspace_coverage_projector; -mod workspace_coverage_projector_service; -mod workspace_coverage_store_binding; -#[allow(dead_code)] -mod workspace_retrieval_coverage; pub use admitted_model_direction_consideration::{ AdmittedModelDirectionConsiderationRequest, AdmittedModelDirectionConsiderationResult, @@ -110,57 +98,19 @@ pub use cultcache_rs::RedbMessagePackBackingStore; pub use cultcache_rs::SingleFileMessagePackBackingStore; pub use cultmesh_integration::EPIPHANY_CANONICAL_SWARM_BRAKE_ID; pub use cultmesh_integration::EPIPHANY_CANONICAL_SWARM_BRAKE_OWNER; -pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_SCHEMA_VERSION; -pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_HEARTBEAT_EVENT_TYPE; -pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_SCHEMA_VERSION; -pub use cultmesh_integration::EPIPHANY_CULTMESH_DAEMON_SERVICE_LIFECYCLE_RECEIPT_TYPE; -pub use cultmesh_integration::EPIPHANY_CULTMESH_LOCAL_AREA_TIER; -pub use cultmesh_integration::EPIPHANY_CULTMESH_LOCAL_AREA_VERSE_ID; -pub use cultmesh_integration::EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION; -pub use cultmesh_integration::EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_TYPE; -pub use cultmesh_integration::EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_SCHEMA_VERSION; -pub use cultmesh_integration::EPIPHANY_CULTMESH_SEMANTIC_PROJECTION_HEALTH_TYPE; -pub use cultmesh_integration::EPIPHANY_CULTMESH_SWARM_BRAKE_KEY; -pub use cultmesh_integration::EPIPHANY_CULTMESH_SWARM_BRAKE_SCHEMA_VERSION; -pub use cultmesh_integration::EPIPHANY_CULTMESH_SWARM_BRAKE_TYPE; -pub use cultmesh_integration::EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID; -pub use cultmesh_integration::EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID; -pub use cultmesh_integration::EpiphanyCultMeshDaemonHeartbeatEventEntry; -pub use cultmesh_integration::EpiphanyCultMeshDaemonServiceLifecycleReceiptEntry; -pub use cultmesh_integration::EpiphanyCultMeshDocuments; -pub use cultmesh_integration::EpiphanyCultMeshManagedServicePolicyEntry; -pub use cultmesh_integration::EpiphanyCultMeshSemanticProjectionHealthEntry; -pub use cultmesh_integration::EpiphanyCultMeshSwarmBrakeEntry; -pub use cultmesh_integration::authenticate_epiphany_cultmesh_semantic_projector_launch; -pub use cultmesh_integration::canonical_epiphany_swarm_brake_protected_surfaces; -pub use cultmesh_integration::default_epiphany_cultmesh_swarm_brake; -pub use cultmesh_integration::engage_epiphany_cultmesh_swarm_brake; -pub use cultmesh_integration::idunn_recover_memory_semantic_projection_from_cultmesh; -pub use cultmesh_integration::load_current_epiphany_cultmesh_daemon_service_lifecycle_receipt_for_service; -pub use cultmesh_integration::load_epiphany_cultmesh_daemon_heartbeat_event; -pub use cultmesh_integration::load_epiphany_cultmesh_daemon_service_lifecycle_receipt; -pub use cultmesh_integration::load_epiphany_cultmesh_managed_service_policies; -pub use cultmesh_integration::load_epiphany_cultmesh_managed_service_policy; -pub use cultmesh_integration::load_epiphany_cultmesh_managed_service_policy_with_digest; -pub use cultmesh_integration::load_epiphany_cultmesh_semantic_projection_health; -pub use cultmesh_integration::load_epiphany_cultmesh_swarm_brake; -pub use cultmesh_integration::load_latest_epiphany_cultmesh_daemon_heartbeat; -pub use cultmesh_integration::open_epiphany_cultmesh_node; -pub use cultmesh_integration::publish_epiphany_cultmesh_semantic_projection_health; -pub use cultmesh_integration::release_epiphany_cultmesh_swarm_brake; -pub use cultmesh_integration::write_epiphany_cultmesh_daemon_heartbeat_event; -pub use cultmesh_integration::write_epiphany_cultmesh_daemon_service_lifecycle_receipt; -pub use cultmesh_integration::write_epiphany_cultmesh_semantic_projector_service_policy; -pub use cultmesh_integration::write_epiphany_cultmesh_swarm_brake; -pub use cultmesh_integration::write_epiphany_cultmesh_workspace_coverage_projector_service_policy; +pub use cultmesh_integration::{ + EPIPHANY_CULTMESH_SWARM_BRAKE_KEY, EPIPHANY_CULTMESH_SWARM_BRAKE_SCHEMA_VERSION, + EPIPHANY_CULTMESH_SWARM_BRAKE_TYPE, EpiphanyCultMeshDocuments, + EpiphanyCultMeshSwarmBrakeEntry, canonical_epiphany_swarm_brake_protected_surfaces, + default_epiphany_cultmesh_swarm_brake, engage_epiphany_cultmesh_swarm_brake, + load_epiphany_cultmesh_swarm_brake, open_epiphany_cultmesh_node, + release_epiphany_cultmesh_swarm_brake, write_epiphany_cultmesh_swarm_brake, +}; + pub use current_work::*; pub use epiphany_state_model::EpiphanyMemoryAnchor; -pub use epiphany_state_model::EpiphanyMemoryContextPacket; -pub use epiphany_state_model::EpiphanyMemoryContextQuery; pub use epiphany_state_model::EpiphanyMemoryDomain; pub use epiphany_state_model::EpiphanyMemoryEdge; -pub use epiphany_state_model::EpiphanyMemoryFreshness; -pub use epiphany_state_model::EpiphanyMemoryFreshnessStatus; pub use epiphany_state_model::EpiphanyMemoryLifecycle; pub use epiphany_state_model::EpiphanyMemoryNode; pub use epiphany_state_model::EpiphanyMemoryProfile; @@ -213,77 +163,18 @@ pub use imagination_consideration::{ validate_current_request as validate_current_imagination_consideration_request, }; pub use memory_graph::EpiphanyMemoryEdgeKind; -pub use memory_graph::EpiphanyMemoryEmbeddingManifest; pub use memory_graph::EpiphanyMemoryGraphSnapshot; pub use memory_graph::EpiphanyMemoryGraphValidationError; pub use memory_graph::EpiphanyMemoryLifecycleReceipt; pub use memory_graph::EpiphanyMemoryNodeKind; -pub use memory_graph::EpiphanyMemoryPatchCandidate; -pub use memory_graph::MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_PROJECTION_ATTEMPT_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_PROJECTION_CLAIM_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_PROJECTION_RETENTION_HEAD_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_PROJECTOR_EXECUTOR_GRANT_SCHEMA_VERSION; -pub use memory_graph::MEMORY_SEMANTIC_PROJECTOR_RECOVERY_AUTHORIZATION_SCHEMA_VERSION; -pub use memory_graph::MemorySemanticIndexConfig; -pub use memory_graph::MemorySemanticIndexReceipt; -pub use memory_graph::MemorySemanticPhysicalRetirementObligation; -pub use memory_graph::MemorySemanticPhysicalRetirementReceipt; -pub use memory_graph::MemorySemanticProjectionAttempt; -pub use memory_graph::MemorySemanticProjectionClaim; -pub use memory_graph::MemorySemanticProjectionHealth; -pub use memory_graph::MemorySemanticProjectionHealthStatus; -pub use memory_graph::MemorySemanticProjectionInput; -pub use memory_graph::MemorySemanticProjectionObligation; -pub use memory_graph::MemorySemanticProjectionObservation; -pub use memory_graph::MemorySemanticProjectionReadiness; -pub use memory_graph::MemorySemanticProjectionRetentionHead; -pub use memory_graph::MemorySemanticProjectionSourceHead; -pub use memory_graph::MemorySemanticProjectorAcquisition; -pub use memory_graph::MemorySemanticProjectorExecutorGrant; -pub use memory_graph::MemorySemanticProjectorPulseClassification; -pub use memory_graph::MemorySemanticProjectorPulseInspection; -pub use memory_graph::MemorySemanticProjectorPulseOutcome; -pub use memory_graph::MemorySemanticProjectorPulseStatus; -pub use memory_graph::MemorySemanticProjectorRecoveryAuthorization; pub use memory_graph::RepoFrontierAdoptedPlan; pub use memory_graph::RepoFrontierItem; pub use memory_graph::RepoFrontierStatus; -pub use memory_graph::SEMANTIC_PROJECTION_SCHEMA_VERSION; -pub use memory_graph::SemanticCanonicalLocator; -pub use memory_graph::SemanticDocumentKind; -pub use memory_graph::SemanticLifecycle; -pub use memory_graph::SemanticProjectionCandidate; -pub use memory_graph::SemanticProjectionDocument; -pub use memory_graph::SemanticVisibility; -pub use memory_graph::authorize_memory_semantic_physical_retirements; -pub use memory_graph::bind_memory_semantic_index_receipt; -pub use memory_graph::compose_memory_graph_snapshots; -pub use memory_graph::derive_memory_graph_freshness; -pub use memory_graph::derive_memory_semantic_projection_health; -pub use memory_graph::derive_memory_semantic_projection_obligation; -pub use memory_graph::derive_semantic_projection; -pub use memory_graph::execute_memory_semantic_physical_retirement; pub use memory_graph::lifecycle_allowed_for_profile; -pub use memory_graph::load_memory_semantic_projection_readiness; -pub use memory_graph::load_memory_semantic_projection_success; pub use memory_graph::memory_graph_domain_id; pub use memory_graph::memory_graph_edge_id; -pub use memory_graph::memory_graph_model_hash; pub use memory_graph::memory_graph_node_id; -pub use memory_graph::memory_semantic_projection_query_eligible; -pub use memory_graph::observe_memory_semantic_projection; -pub use memory_graph::plan_memory_graph_context_cut; -pub use memory_graph::plan_memory_graph_context_cut_with_ranked_ids; -pub use memory_graph::resolve_semantic_candidate; -pub use memory_graph::retain_memory_semantic_projection_lifecycles; -pub use memory_graph::semantic_memory_context; -pub use memory_graph::semantic_point_id; pub use memory_graph::validate_memory_graph_snapshot; -pub use memory_graph::validate_memory_semantic_projection_attempt; -pub use memory_graph::validate_memory_semantic_projection_obligation; pub use mind_documents::*; pub use packaged_release::{ EPIPHANY_PACKAGED_RELEASE_HEAD_SCHEMA_VERSION, EPIPHANY_PACKAGED_RELEASE_SCHEMA_VERSION, @@ -339,8 +230,6 @@ pub use persona_turn::parse_and_validate_persona_interpreter_effect_set; pub use persona_turn::persona_interpreter_effect_set_json_schema; pub use persona_turn::persona_projected_surface_is_clean; pub use persona_turn::put_persona_terminal_decision; -pub use persona_turn::render_persona_semantic_memory_recall; -pub use persona_turn::semantic_memory_recall_from_heartbeat_action; pub use process_observation::EpiphanyProcessObservation; pub use process_observation::ProcessInstanceIdentity; pub use process_observation::ProcessInstanceObservation; @@ -357,7 +246,6 @@ pub use reorientation_work::*; pub use repo_model_documents::*; pub use repo_model_gateway::*; pub use repository_body_observer::*; -pub use repository_readiness::*; pub use resident_readiness::*; pub use resident_self::*; pub use runtime_spine::ARCHIVED_RUNTIME_SESSION_SCHEMA_VERSION; @@ -493,7 +381,6 @@ pub use runtime_spine::runtime_hello_frame; pub use runtime_spine::runtime_job_snapshot; pub use runtime_spine::runtime_latest_hands_receipt_chain_after; pub use runtime_spine::runtime_latest_repo_frontier_relinquishment; -pub use runtime_spine::runtime_modeling_semantic_projection_input; pub use runtime_spine::runtime_registered_document_types; pub use runtime_spine::runtime_reorient_worker_result; pub use runtime_spine::runtime_repo_frontier_plan_decision; @@ -528,8 +415,6 @@ pub use runtime_spine::validate_hands_action_authority; pub use runtime_spine::write_runtime_hello_frame; pub use runtime_spine::write_runtime_schema_catalog_json; pub use runtime_worker_attempt::{RuntimeTypedRequestRef, WorkerProcessStatus}; -pub use semantic_projector_service::SemanticProjectorServiceBody; -pub use semantic_projector_service::SemanticProjectorServicePulse; pub use soul_gateway::*; pub use state_ledger::EpiphanyBranchRecord; pub use state_ledger::EpiphanyLedgerEvidenceRecord; @@ -586,67 +471,4 @@ pub use surfaces::derive_role_board; pub use surfaces::interpret_runtime_reorient_worker_result; pub use surfaces::interpret_runtime_role_worker_result; pub use surfaces::recommend_coordinator_action; -pub use workspace_coverage_process_bootstrap::{ - WorkspaceCoverageProcessBootstrap, read_workspace_coverage_process_bootstrap, - write_workspace_coverage_process_bootstrap, -}; -pub use workspace_coverage_process_documents::{ - WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION, WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_TYPE, - WORKSPACE_COVERAGE_CLAIM_SIGHT_SCHEMA_VERSION, WORKSPACE_COVERAGE_CLAIM_SIGHT_TYPE, - WORKSPACE_COVERAGE_PROCESS_LAUNCH_LATEST_KEY, WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROCESS_LAUNCH_TYPE, WORKSPACE_COVERAGE_PROCESS_TERMINATION_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROCESS_TERMINATION_TYPE, WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_LATEST_KEY, - WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_TYPE, - WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_SCHEMA_VERSION, - WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_TYPE, WORKSPACE_COVERAGE_TERMINAL_SIGHT_SCHEMA_VERSION, - WORKSPACE_COVERAGE_TERMINAL_SIGHT_TYPE, WorkspaceCoverageAdvancementSightEntry, - WorkspaceCoverageClaimSightEntry, WorkspaceCoverageManagedProcessLaunchEntry, - WorkspaceCoverageProcessLifecycleObservation, - WorkspaceCoverageProcessTerminationObservationEntry, WorkspaceCoverageProviderHeartbeatEntry, - WorkspaceCoverageRecoveryDirectiveEntry, WorkspaceCoverageTerminalSightEntry, - authenticate_current_workspace_coverage_advancement_sight, - authenticate_current_workspace_coverage_claim_sight, - authenticate_current_workspace_coverage_terminal_sight, - authenticate_historical_workspace_coverage_managed_process_launch, - authenticate_recovery_workspace_coverage_claim_sight, - authenticate_workspace_coverage_managed_process_launch, - authenticate_workspace_coverage_process_termination_observation, - authenticate_workspace_coverage_provider_heartbeat, - authenticate_workspace_coverage_replacement_lineage, - authenticate_workspace_coverage_termination_with_envelope_digest, - load_latest_workspace_coverage_managed_process_launch, - load_latest_workspace_coverage_provider_heartbeat, - load_workspace_coverage_managed_process_launch, - load_workspace_coverage_managed_process_launch_with_digest, - load_workspace_coverage_process_termination_observation, - load_workspace_coverage_provider_heartbeat, - observe_historical_workspace_coverage_managed_process, - observe_workspace_coverage_managed_process, process_identity_from_workspace_coverage_launch, - sign_workspace_coverage_heartbeat, sign_workspace_coverage_launch, - sign_workspace_coverage_termination, workspace_coverage_heartbeat_statement, - workspace_coverage_host_identity_record_digest, workspace_coverage_launch_statement, - workspace_coverage_termination_statement, write_workspace_coverage_managed_process_launch, - write_workspace_coverage_process_termination_observation, - write_workspace_coverage_provider_heartbeat, write_workspace_coverage_recovery_directive, -}; -pub use workspace_coverage_projection_progress::{ - WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION, - WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE, WorkspaceCoverageAdvancingAuthority, - WorkspaceCoverageProjectionProgressEntry, authenticate_current_workspace_coverage_advancement, - authenticate_workspace_coverage_projection_progress, - load_latest_workspace_coverage_projection_progress, - load_workspace_coverage_projection_progress, -}; -pub use workspace_coverage_projector::{ - WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, WorkspaceCoverageRecoveryOutcome, - WorkspaceCoverageTerminalAuthority, authenticate_current_workspace_coverage_terminal_authority, - authenticate_workspace_coverage_recovery_receipt, -}; -pub use workspace_coverage_projector_service::WorkspaceCoverageProjectorConfig; -pub use workspace_coverage_projector_service::WorkspaceCoverageProjectorPulseStatus; -pub use workspace_coverage_projector_service::WorkspaceCoverageProjectorServiceBody; -pub use workspace_coverage_projector_service::WorkspaceCoverageProjectorServicePulse; -pub use workspace_coverage_store_binding::*; -pub use workspace_retrieval_coverage::*; mod admitted_model_direction_consideration; diff --git a/epiphany-core/src/memory_graph/compose.rs b/epiphany-core/src/memory_graph/compose.rs deleted file mode 100644 index f480b6e9..00000000 --- a/epiphany-core/src/memory_graph/compose.rs +++ /dev/null @@ -1,93 +0,0 @@ -use super::EpiphanyMemoryFreshness; -use super::EpiphanyMemoryFreshnessStatus; -use super::EpiphanyMemoryGraphSnapshot; -use super::EpiphanyMemoryGraphValidationError; -use super::validate_memory_graph_snapshot; -use crate::memory_graph::MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION; - -pub fn compose_memory_graph_snapshots( - graph_id: impl Into, - snapshots: impl IntoIterator, -) -> Result> { - let mut composed = EpiphanyMemoryGraphSnapshot { - schema_version: Some(MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION.to_string()), - graph_id: graph_id.into(), - ..Default::default() - }; - - let mut freshness_notes = Vec::new(); - for snapshot in snapshots { - composed.domains.extend(snapshot.domains); - composed.nodes.extend(snapshot.nodes); - composed.edges.extend(snapshot.edges); - composed.summaries.extend(snapshot.summaries); - composed - .lifecycle_receipts - .extend(snapshot.lifecycle_receipts); - if let Some(freshness) = snapshot.freshness { - merge_freshness(&mut composed, freshness, &mut freshness_notes); - } - } - - if let Some(freshness) = composed.freshness.as_mut() { - if freshness.note.is_none() && !freshness_notes.is_empty() { - freshness.note = Some(freshness_notes.join(" ")); - } - } - - let errors = validate_memory_graph_snapshot(&composed); - if errors.is_empty() { - Ok(composed) - } else { - Err(errors) - } -} - -fn merge_freshness( - composed: &mut EpiphanyMemoryGraphSnapshot, - freshness: EpiphanyMemoryFreshness, - notes: &mut Vec, -) { - let aggregate = composed - .freshness - .get_or_insert_with(|| EpiphanyMemoryFreshness { - status: EpiphanyMemoryFreshnessStatus::Ready, - note: None, - ..Default::default() - }); - - if freshness_rank(freshness.status) > freshness_rank(aggregate.status) { - aggregate.status = freshness.status; - } - merge_unique(&mut aggregate.stale_node_ids, freshness.stale_node_ids); - merge_unique(&mut aggregate.stale_edge_ids, freshness.stale_edge_ids); - merge_unique( - &mut aggregate.stale_summary_ids, - freshness.stale_summary_ids, - ); - merge_unique( - &mut aggregate.dirty_source_hashes, - freshness.dirty_source_hashes, - ); - if let Some(note) = freshness.note { - if !note.trim().is_empty() { - notes.push(note); - } - } -} - -fn freshness_rank(status: EpiphanyMemoryFreshnessStatus) -> u8 { - match status { - EpiphanyMemoryFreshnessStatus::Stale => 2, - EpiphanyMemoryFreshnessStatus::Ready => 1, - _ => 0, - } -} - -fn merge_unique(target: &mut Vec, values: impl IntoIterator) { - for value in values { - if !target.iter().any(|existing| existing == &value) { - target.push(value); - } - } -} diff --git a/epiphany-core/src/memory_graph/context_cut.rs b/epiphany-core/src/memory_graph/context_cut.rs deleted file mode 100644 index 119bb511..00000000 --- a/epiphany-core/src/memory_graph/context_cut.rs +++ /dev/null @@ -1,693 +0,0 @@ -use super::EpiphanyMemoryAnchor; -use super::EpiphanyMemoryContextPacket; -use super::EpiphanyMemoryContextQuery; -use super::EpiphanyMemoryEdge; -use super::EpiphanyMemoryFreshnessStatus; -use super::EpiphanyMemoryGraphSnapshot; -use super::EpiphanyMemoryNode; -use super::EpiphanyMemoryProfile; -use super::EpiphanyMemorySummary; -use super::RepoFrontierItem; -use super::RepoFrontierStatus; -use super::derive_memory_graph_freshness; -use super::ids::normalized_key; -use super::ids::stable_memory_graph_id; -use super::memory_graph_model_hash; -use bm25::Document; -use bm25::Language; -use bm25::SearchEngineBuilder; -use std::collections::HashMap; -use std::collections::HashSet; - -pub fn plan_memory_graph_context_cut( - snapshot: &EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, -) -> EpiphanyMemoryContextPacket { - plan_memory_graph_context_cut_constrained(snapshot, query, &[], false) -} - -pub fn plan_memory_graph_context_cut_with_ranked_ids( - snapshot: &EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, - ranked_document_ids: &[String], -) -> EpiphanyMemoryContextPacket { - plan_memory_graph_context_cut_constrained(snapshot, query, ranked_document_ids, false) -} - -pub(crate) fn plan_modeling_context_cut( - snapshot: &EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, - ranked_document_ids: &[String], -) -> EpiphanyMemoryContextPacket { - plan_memory_graph_context_cut_constrained(snapshot, query, ranked_document_ids, true) -} - -fn plan_memory_graph_context_cut_constrained( - snapshot: &EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, - ranked_document_ids: &[String], - modeling_only: bool, -) -> EpiphanyMemoryContextPacket { - let budget = query.budget.unwrap_or(12).clamp(1, 64) as usize; - let dirty_source_hashes = snapshot - .freshness - .as_ref() - .map(|freshness| freshness.dirty_source_hashes.as_slice()) - .unwrap_or(&[]); - let freshness = derive_memory_graph_freshness(snapshot, dirty_source_hashes); - let stale_nodes: HashSet<&str> = freshness - .stale_node_ids - .iter() - .map(String::as_str) - .collect(); - let stale_edges: HashSet<&str> = freshness - .stale_edge_ids - .iter() - .map(String::as_str) - .collect(); - let stale_summaries: HashSet<&str> = freshness - .stale_summary_ids - .iter() - .map(String::as_str) - .collect(); - - let domains = query - .domain_ids - .iter() - .map(String::as_str) - .collect::>(); - let requested_nodes = query - .node_ids - .iter() - .map(String::as_str) - .collect::>(); - let requested_edges = query - .edge_ids - .iter() - .map(String::as_str) - .collect::>(); - let terms = query_terms(query); - - let node_by_id = snapshot - .nodes - .iter() - .map(|node| (node.id.as_str(), node)) - .collect::>(); - let edge_by_id = snapshot - .edges - .iter() - .map(|edge| (edge.id.as_str(), edge)) - .collect::>(); - - let mut nodes = Vec::new(); - let mut edges = Vec::new(); - let mut summaries: Vec = Vec::new(); - let mut warnings = Vec::new(); - - // Modeling's unresolved frontier is explicit routing authority. Preserve its - // stored order and exact claim targets before asking semantic retrieval to - // infer what matters from the launch prose. - let (frontier, rejected_frontier_ids) = dependency_ordered_frontier( - snapshot, - query, - modeling_only, - budget, - &node_by_id, - &stale_nodes, - &domains, - ); - for id in rejected_frontier_ids { - warnings.push(format!( - "frontier {id} was omitted because its target claims are missing, stale, or retired" - )); - } - for node_id in frontier - .iter() - .flat_map(|item| item.target_claim_ids.iter()) - { - if let Some(node) = node_by_id.get(node_id.as_str()) { - push_unique_node(&mut nodes, (*node).clone(), budget); - } - } - - // Semantic projection may rank canonical document identities, never - // payload-authored claim text. Explicit frontier remains first; ranked - // canonical objects then seed the cut before BM25 fills remaining space. - for document_id in ranked_document_ids { - if let Some(node) = node_by_id.get(document_id.as_str()) { - if !stale_nodes.contains(node.id.as_str()) - && node_matches(node, query.profile, modeling_only, &domains, &[]) - { - push_unique_node(&mut nodes, (*node).clone(), budget); - } - continue; - } - if let Some(edge) = edge_by_id.get(document_id.as_str()) { - let endpoints_live = [edge.source_id.as_str(), edge.target_id.as_str()] - .into_iter() - .all(|id| !stale_nodes.contains(id)); - if !stale_edges.contains(edge.id.as_str()) - && endpoints_live - && edge_matches(edge, query.profile, modeling_only, &domains, &node_by_id) - { - push_unique_edge(&mut edges, (*edge).clone(), budget); - if let Some(node) = node_by_id.get(edge.source_id.as_str()) { - if !stale_nodes.contains(node.id.as_str()) - && node_matches(node, query.profile, modeling_only, &domains, &[]) - { - push_unique_node(&mut nodes, (*node).clone(), budget); - } - } - if let Some(node) = node_by_id.get(edge.target_id.as_str()) { - if !stale_nodes.contains(node.id.as_str()) - && node_matches(node, query.profile, modeling_only, &domains, &[]) - { - push_unique_node(&mut nodes, (*node).clone(), budget); - } - } - } - continue; - } - if let Some(summary) = snapshot - .summaries - .iter() - .find(|summary| summary.id == *document_id) - && summary_matches( - summary, - query.profile, - modeling_only, - &domains, - &[], - &node_by_id, - ) - && summary_is_usable(summary, &stale_summaries) - && summaries.len() < budget - && !summaries.iter().any(|existing| existing.id == summary.id) - { - summaries.push(summary.clone()); - } - } - - for summary in ranked_summaries( - snapshot, - query, - modeling_only, - &domains, - &terms, - &node_by_id, - ) { - if summaries.len() >= budget { - break; - } - if !summary_matches( - summary, - query.profile, - modeling_only, - &domains, - &terms, - &node_by_id, - ) { - continue; - } - if summary_is_usable(summary, &stale_summaries) { - if !summaries.iter().any(|existing| existing.id == summary.id) { - summaries.push(summary.clone()); - } - continue; - } - warnings.push(format!( - "summary {} is stale or low-confidence; descended into children", - summary.id - )); - include_summary_children( - summary, - &node_by_id, - &edge_by_id, - &stale_nodes, - &stale_edges, - query.profile, - modeling_only, - &domains, - budget, - &mut nodes, - &mut edges, - ); - } - - for node_id in &query.node_ids { - if let Some(node) = node_by_id.get(node_id.as_str()) { - if !stale_nodes.contains(node.id.as_str()) - && node_matches(node, query.profile, modeling_only, &domains, &[]) - { - push_unique_node(&mut nodes, (*node).clone(), budget); - } - } - } - for edge_id in &query.edge_ids { - if let Some(edge) = edge_by_id.get(edge_id.as_str()) { - if !stale_edges.contains(edge.id.as_str()) - && edge_matches(edge, query.profile, modeling_only, &domains, &node_by_id) - { - push_unique_edge(&mut edges, (*edge).clone(), budget); - for node_id in [&edge.source_id, &edge.target_id] { - if let Some(node) = node_by_id.get(node_id.as_str()) - && !stale_nodes.contains(node.id.as_str()) - && node_matches(node, query.profile, modeling_only, &domains, &[]) - { - push_unique_node(&mut nodes, (*node).clone(), budget); - } - } - } - } - } - - if summaries.is_empty() && nodes.is_empty() { - for node in ranked_nodes( - snapshot, - query, - modeling_only, - &domains, - &terms, - &stale_nodes, - ) { - if nodes.len() >= budget { - break; - } - if node_matches(node, query.profile, modeling_only, &domains, &terms) { - push_unique_node(&mut nodes, node.clone(), budget); - } - } - } - - let anchors = unique_anchors( - nodes - .iter() - .flat_map(|node| node.anchors.iter()) - .chain(edges.iter().flat_map(|edge| edge.anchors.iter())), - ); - - EpiphanyMemoryContextPacket { - id: stable_memory_graph_id("memctx", [query.id.as_str(), snapshot.graph_id.as_str()]), - query_id: query.id.clone(), - repo_model_revision: snapshot.model_revision, - repo_model_hash: memory_graph_model_hash(snapshot).unwrap_or_default(), - nodes, - edges, - summaries, - frontier, - anchors, - warnings, - missing_node_ids: query - .node_ids - .iter() - .filter(|id| !requested_nodes.is_empty() && !node_by_id.contains_key(id.as_str())) - .cloned() - .collect(), - missing_edge_ids: query - .edge_ids - .iter() - .filter(|id| !requested_edges.is_empty() && !edge_by_id.contains_key(id.as_str())) - .cloned() - .collect(), - } -} - -fn dependency_ordered_frontier( - snapshot: &EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, - modeling_only: bool, - budget: usize, - node_by_id: &HashMap<&str, &EpiphanyMemoryNode>, - stale_nodes: &HashSet<&str>, - domains: &HashSet<&str>, -) -> (Vec, Vec) { - let unresolved = snapshot - .frontier - .iter() - .filter(|item| { - matches!( - item.status, - RepoFrontierStatus::Active - | RepoFrontierStatus::Proposed - | RepoFrontierStatus::Blocked - ) - }) - .collect::>(); - let unresolved_ids = unresolved - .iter() - .map(|item| item.id.as_str()) - .collect::>(); - let mut eligible_ids = unresolved - .iter() - .filter(|item| { - !item.target_claim_ids.is_empty() - && item.target_claim_ids.iter().all(|id| { - node_by_id.get(id.as_str()).is_some_and(|node| { - !matches!( - node.lifecycle, - super::EpiphanyMemoryLifecycle::Retired - | super::EpiphanyMemoryLifecycle::Stale - ) && !stale_nodes.contains(id.as_str()) - && node_matches(node, query.profile, modeling_only, domains, &[]) - }) - }) - }) - .map(|item| item.id.as_str()) - .collect::>(); - loop { - let before = eligible_ids.len(); - let current_eligible = eligible_ids.clone(); - eligible_ids.retain(|id| { - unresolved - .iter() - .find(|item| item.id == *id) - .is_some_and(|item| { - item.dependency_item_ids.iter().all(|dependency| { - !unresolved_ids.contains(dependency.as_str()) - || current_eligible.contains(dependency.as_str()) - }) - }) - }); - if eligible_ids.len() == before { - break; - } - } - let rejected = unresolved - .iter() - .filter(|item| !eligible_ids.contains(item.id.as_str())) - .map(|item| item.id.clone()) - .collect(); - let eligible = unresolved - .into_iter() - .filter(|item| eligible_ids.contains(item.id.as_str())) - .map(|item| (item.id.as_str(), item)) - .collect::>(); - let mut ordered = Vec::new(); - let mut complete = HashSet::new(); - let mut visiting = HashSet::new(); - for item in &snapshot.frontier { - append_frontier_prerequisites( - &item.id, - &eligible, - &mut visiting, - &mut complete, - &mut ordered, - ); - } - ( - ordered.into_iter().take(budget).cloned().collect(), - rejected, - ) -} - -fn append_frontier_prerequisites<'a>( - id: &'a str, - eligible: &HashMap<&'a str, &'a RepoFrontierItem>, - visiting: &mut HashSet<&'a str>, - complete: &mut HashSet<&'a str>, - ordered: &mut Vec<&'a RepoFrontierItem>, -) { - if complete.contains(id) || !visiting.insert(id) { - return; - } - let Some(item) = eligible.get(id).copied() else { - visiting.remove(id); - return; - }; - for dependency in &item.dependency_item_ids { - append_frontier_prerequisites(dependency, eligible, visiting, complete, ordered); - } - visiting.remove(id); - if complete.insert(id) { - ordered.push(item); - } -} - -fn ranked_nodes<'a>( - snapshot: &'a EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, - modeling_only: bool, - domain_ids: &HashSet<&str>, - terms: &[String], - stale_nodes: &HashSet<&str>, -) -> Vec<&'a EpiphanyMemoryNode> { - let eligible = snapshot - .nodes - .iter() - .filter(|node| { - node_matches(node, query.profile, modeling_only, domain_ids, &[]) - && !stale_nodes.contains(node.id.as_str()) - }) - .collect::>(); - rank_typed_documents(eligible, query.text.as_deref(), terms, |node| { - [ - node.title.as_str(), - node.claim.as_str(), - node.question.as_str(), - node.tension.as_str(), - node.action_implication.as_str(), - ] - .join(" ") - }) -} - -fn ranked_summaries<'a>( - snapshot: &'a EpiphanyMemoryGraphSnapshot, - query: &EpiphanyMemoryContextQuery, - modeling_only: bool, - domain_ids: &HashSet<&str>, - terms: &[String], - node_by_id: &HashMap<&str, &EpiphanyMemoryNode>, -) -> Vec<&'a EpiphanyMemorySummary> { - let eligible = snapshot - .summaries - .iter() - .filter(|summary| { - summary_matches( - summary, - query.profile, - modeling_only, - domain_ids, - &[], - node_by_id, - ) - }) - .collect::>(); - rank_typed_documents(eligible, query.text.as_deref(), terms, |summary| { - [ - summary.target.as_str(), - summary.claim.as_str(), - summary.question.as_str(), - summary.tension.as_str(), - summary.action_implication.as_str(), - ] - .join(" ") - }) -} - -fn rank_typed_documents<'a, T>( - eligible: Vec<&'a T>, - query: Option<&str>, - terms: &[String], - search_text: impl Fn(&T) -> String, -) -> Vec<&'a T> { - if eligible.is_empty() || terms.is_empty() { - return eligible; - } - let documents = eligible - .iter() - .enumerate() - .map(|(index, value)| Document::new(index, search_text(value))) - .collect::>(); - let engine = SearchEngineBuilder::::with_documents(Language::English, documents).build(); - engine - .search(query.unwrap_or_default(), eligible.len()) - .into_iter() - .filter_map(|result| eligible.get(result.document.id).copied()) - .collect() -} - -fn query_terms(query: &EpiphanyMemoryContextQuery) -> Vec { - query - .text - .as_deref() - .unwrap_or_default() - .split(|ch: char| !ch.is_alphanumeric() && ch != '_') - .filter(|term| term.len() > 2) - .map(normalized_key) - .collect() -} - -fn summary_matches( - summary: &EpiphanyMemorySummary, - profile: Option, - modeling_only: bool, - domain_ids: &HashSet<&str>, - terms: &[String], - node_by_id: &HashMap<&str, &EpiphanyMemoryNode>, -) -> bool { - if !domain_ids.is_empty() && !domain_ids.contains(summary.domain_id.as_str()) { - return false; - } - let covers_partition = summary - .covers_node_ids - .iter() - .filter_map(|id| node_by_id.get(id.as_str())) - .any(|node| modeling_scope_matches(node.profile, modeling_only)); - if modeling_only && !covers_partition { - return false; - } - if let Some(profile) = profile { - let covers_profile = summary - .covers_node_ids - .iter() - .filter_map(|id| node_by_id.get(id.as_str())) - .any(|node| node.profile == profile); - if !covers_profile { - return false; - } - } - terms.is_empty() - || text_matches_terms( - [ - &summary.target, - &summary.claim, - &summary.question, - &summary.tension, - ], - terms, - ) -} - -fn node_matches( - node: &EpiphanyMemoryNode, - profile: Option, - modeling_only: bool, - domain_ids: &HashSet<&str>, - terms: &[String], -) -> bool { - if profile.is_some_and(|profile| node.profile != profile) { - return false; - } - if !modeling_scope_matches(node.profile, modeling_only) { - return false; - } - if !domain_ids.is_empty() && !domain_ids.contains(node.domain_id.as_str()) { - return false; - } - terms.is_empty() - || text_matches_terms( - [ - &node.title, - &node.claim, - &node.question, - &node.tension, - &node.action_implication, - ], - terms, - ) -} - -fn edge_matches( - edge: &EpiphanyMemoryEdge, - profile: Option, - modeling_only: bool, - domain_ids: &HashSet<&str>, - node_by_id: &HashMap<&str, &EpiphanyMemoryNode>, -) -> bool { - if profile.is_some_and(|profile| edge.profile != profile) - || !modeling_scope_matches(edge.profile, modeling_only) - { - return false; - } - [&edge.source_id, &edge.target_id].into_iter().all(|id| { - node_by_id.get(id.as_str()).is_some_and(|node| { - modeling_scope_matches(node.profile, modeling_only) - && (domain_ids.is_empty() || domain_ids.contains(node.domain_id.as_str())) - }) - }) -} - -fn modeling_scope_matches(profile: EpiphanyMemoryProfile, modeling_only: bool) -> bool { - !modeling_only - || matches!( - profile, - EpiphanyMemoryProfile::RepoArchitecture | EpiphanyMemoryProfile::RepoDataflow - ) -} - -fn text_matches_terms<'a>(values: impl IntoIterator, terms: &[String]) -> bool { - let joined = values - .into_iter() - .map(|value| value.to_lowercase()) - .collect::>() - .join(" "); - terms.iter().any(|term| joined.contains(term)) -} - -fn summary_is_usable(summary: &EpiphanyMemorySummary, stale_summaries: &HashSet<&str>) -> bool { - summary.freshness == EpiphanyMemoryFreshnessStatus::Ready - && summary.confidence >= 70 - && !stale_summaries.contains(summary.id.as_str()) - && summary.known_omissions.is_empty() -} - -fn include_summary_children( - summary: &EpiphanyMemorySummary, - node_by_id: &HashMap<&str, &EpiphanyMemoryNode>, - edge_by_id: &HashMap<&str, &EpiphanyMemoryEdge>, - stale_nodes: &HashSet<&str>, - stale_edges: &HashSet<&str>, - profile: Option, - modeling_only: bool, - domain_ids: &HashSet<&str>, - budget: usize, - nodes: &mut Vec, - edges: &mut Vec, -) { - for node_id in &summary.covers_node_ids { - if let Some(node) = node_by_id.get(node_id.as_str()) { - if stale_nodes.contains(node.id.as_str()) - || !node_matches(node, profile, modeling_only, domain_ids, &[]) - { - continue; - } - push_unique_node(nodes, (*node).clone(), budget); - } - } - for edge_id in &summary.covers_edge_ids { - if let Some(edge) = edge_by_id.get(edge_id.as_str()) { - if stale_edges.contains(edge.id.as_str()) - || !edge_matches(edge, profile, modeling_only, domain_ids, node_by_id) - { - continue; - } - push_unique_edge(edges, (*edge).clone(), budget); - } - } -} - -fn unique_anchors<'a>( - anchors: impl IntoIterator, -) -> Vec { - let mut out = Vec::new(); - let mut seen = HashSet::new(); - for anchor in anchors { - if seen.insert(anchor.id.as_str()) { - out.push(anchor.clone()); - } - } - out -} - -fn push_unique_node(target: &mut Vec, node: EpiphanyMemoryNode, budget: usize) { - if target.len() < budget && !target.iter().any(|existing| existing.id == node.id) { - target.push(node); - } -} - -fn push_unique_edge(target: &mut Vec, edge: EpiphanyMemoryEdge, budget: usize) { - if target.len() < budget && !target.iter().any(|existing| existing.id == edge.id) { - target.push(edge); - } -} diff --git a/epiphany-core/src/memory_graph/freshness.rs b/epiphany-core/src/memory_graph/freshness.rs deleted file mode 100644 index ef3d2cc5..00000000 --- a/epiphany-core/src/memory_graph/freshness.rs +++ /dev/null @@ -1,84 +0,0 @@ -use super::EpiphanyMemoryFreshness; -use super::EpiphanyMemoryFreshnessStatus; -use super::EpiphanyMemoryGraphSnapshot; -use super::EpiphanyMemoryLifecycle; -use super::push_unique; -use super::unique_strings; -use std::collections::HashSet; - -pub fn derive_memory_graph_freshness( - snapshot: &EpiphanyMemoryGraphSnapshot, - dirty_source_hashes: &[String], -) -> EpiphanyMemoryFreshness { - let dirty: HashSet<&str> = dirty_source_hashes.iter().map(String::as_str).collect(); - let mut stale_node_ids = Vec::new(); - let mut stale_edge_ids = Vec::new(); - let mut stale_summary_ids = Vec::new(); - - for node in &snapshot.nodes { - if node.lifecycle == EpiphanyMemoryLifecycle::Stale - || node - .source_hashes - .iter() - .any(|hash| dirty.contains(hash.as_str())) - { - push_unique(&mut stale_node_ids, node.id.clone()); - } - } - - for edge in &snapshot.edges { - if edge.lifecycle == EpiphanyMemoryLifecycle::Stale - || edge - .anchors - .iter() - .filter_map(|anchor| anchor.source_hash.as_deref()) - .any(|hash| dirty.contains(hash)) - { - push_unique(&mut stale_edge_ids, edge.id.clone()); - } - } - - for summary in &snapshot.summaries { - if summary.freshness == EpiphanyMemoryFreshnessStatus::Stale - || summary - .source_hashes - .iter() - .any(|hash| dirty.contains(hash.as_str())) - || summary - .covers_node_ids - .iter() - .any(|id| stale_node_ids.iter().any(|stale| stale == id)) - || summary - .covers_edge_ids - .iter() - .any(|id| stale_edge_ids.iter().any(|stale| stale == id)) - { - push_unique(&mut stale_summary_ids, summary.id.clone()); - } - } - - let status = if stale_node_ids.is_empty() - && stale_edge_ids.is_empty() - && stale_summary_ids.is_empty() - && dirty_source_hashes.is_empty() - { - EpiphanyMemoryFreshnessStatus::Ready - } else { - EpiphanyMemoryFreshnessStatus::Stale - }; - - EpiphanyMemoryFreshness { - status, - stale_node_ids, - stale_edge_ids, - stale_summary_ids, - dirty_source_hashes: unique_strings(dirty_source_hashes.iter().cloned()), - note: Some(match status { - EpiphanyMemoryFreshnessStatus::Ready => "Memory graph is ready.".to_string(), - EpiphanyMemoryFreshnessStatus::Stale => { - "Memory graph has stale source-backed records.".to_string() - } - _ => "Memory graph freshness is not derived.".to_string(), - }), - } -} diff --git a/epiphany-core/src/memory_graph/mod.rs b/epiphany-core/src/memory_graph/mod.rs index 2bdd3a01..f787a9de 100644 --- a/epiphany-core/src/memory_graph/mod.rs +++ b/epiphany-core/src/memory_graph/mod.rs @@ -1,79 +1,26 @@ -pub mod compose; -pub mod context_cut; -pub mod freshness; pub mod ids; pub mod profiles; -pub mod semantic_index; -pub mod semantic_projection; -pub mod semantic_projector; -pub mod semantic_projector_pulse; pub mod validation; -pub use epiphany_state_model::EpiphanyMemoryAnchor; -pub use epiphany_state_model::EpiphanyMemoryContextPacket; -pub use epiphany_state_model::EpiphanyMemoryContextQuery; pub use epiphany_state_model::EpiphanyMemoryDomain; pub use epiphany_state_model::EpiphanyMemoryEdge; pub use epiphany_state_model::EpiphanyMemoryEdgeKind; -pub use epiphany_state_model::EpiphanyMemoryEmbeddingManifest; -pub use epiphany_state_model::EpiphanyMemoryFreshness; -pub use epiphany_state_model::EpiphanyMemoryFreshnessStatus; pub use epiphany_state_model::EpiphanyMemoryGraphSnapshot; pub use epiphany_state_model::EpiphanyMemoryLifecycle; pub use epiphany_state_model::EpiphanyMemoryLifecycleReceipt; pub use epiphany_state_model::EpiphanyMemoryNode; pub use epiphany_state_model::EpiphanyMemoryNodeKind; -pub use epiphany_state_model::EpiphanyMemoryPatchCandidate; pub use epiphany_state_model::EpiphanyMemoryProfile; pub use epiphany_state_model::EpiphanyMemorySummary; pub use epiphany_state_model::RepoFrontierAdoptedPlan; pub use epiphany_state_model::RepoFrontierItem; pub use epiphany_state_model::RepoFrontierStatus; -pub use compose::compose_memory_graph_snapshots; -pub use context_cut::plan_memory_graph_context_cut; -pub use context_cut::plan_memory_graph_context_cut_with_ranked_ids; -pub(crate) use context_cut::plan_modeling_context_cut; -pub use freshness::derive_memory_graph_freshness; pub use ids::memory_graph_domain_id; pub use ids::memory_graph_edge_id; pub use ids::memory_graph_node_id; -pub use semantic_index::*; -pub use semantic_projection::*; -pub use semantic_projector::*; -pub use semantic_projector_pulse::*; pub use validation::EpiphanyMemoryGraphValidationError; pub(crate) use validation::frontier_item_has_routeable_repository_scope; pub use validation::lifecycle_allowed_for_profile; pub(crate) use validation::repo_paths_are_canonical_and_safe; pub use validation::validate_memory_graph_snapshot; - -pub(crate) fn push_unique(target: &mut Vec, value: String) { - if !target.iter().any(|existing| existing == &value) { - target.push(value); - } -} - -pub(crate) fn unique_strings(values: impl IntoIterator) -> Vec { - let mut out = Vec::new(); - for value in values { - push_unique(&mut out, value); - } - out -} - -pub const MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION: &str = "epiphany.memory_graph.projection.v1"; - -/// Digest helper for transient memory-context and semantic projection DTOs. -/// This digest is derived notification state; keyed Mind documents own the -/// RepoModel and no aggregate revision can be committed through this module. -pub fn memory_graph_model_hash(snapshot: &EpiphanyMemoryGraphSnapshot) -> anyhow::Result { - use sha2::{Digest, Sha256}; - - let mut canonical = snapshot.clone(); - canonical.model_hash.clear(); - Ok(format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(&canonical)?) - )) -} diff --git a/epiphany-core/src/memory_graph/semantic_index.rs b/epiphany-core/src/memory_graph/semantic_index.rs deleted file mode 100644 index df465a13..00000000 --- a/epiphany-core/src/memory_graph/semantic_index.rs +++ /dev/null @@ -1,1841 +0,0 @@ -use super::{ - EpiphanyMemoryContextPacket, EpiphanyMemoryContextQuery, EpiphanyMemoryGraphSnapshot, - SEMANTIC_PROJECTION_SCHEMA_VERSION, SemanticProjectionCandidate, SemanticProjectionDocument, - derive_semantic_projection, plan_modeling_context_cut, resolve_semantic_candidate, -}; -use crate::semantic_backend::{ - CollectionCompatibility, OllamaConfig, OllamaEmbedder, QdrantBackend, QdrantConfig, - SemanticPoint, -}; -use anyhow::{Result, anyhow}; -use cultcache_rs::{CacheBackingStore, DatabaseEntry, SingleFileMessagePackBackingStore}; -use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use std::collections::{BTreeMap, HashSet}; -use std::env; -use std::path::Path; -use uuid::Uuid; - -pub const MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_index_receipt.v2"; -pub const MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_projection_obligation.v0"; -pub const MEMORY_SEMANTIC_PROJECTION_ATTEMPT_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_projection_attempt.v1"; -const MODELING_COLLECTION_DEFAULT: &str = "epiphany_modeling_v1"; -const MODELING_PARTITION: &str = "modeling"; -const QUERY_LIMIT_MAX: usize = 64; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MemorySemanticIndexConfig { - pub qdrant_url: String, - pub qdrant_api_key: Option, - pub qdrant_timeout_ms: u64, - pub ollama_base_url: String, - pub ollama_model: String, - pub ollama_timeout_ms: u64, - pub embedding_provider_id: String, - pub modeling_collection: String, - pub modeling_query_instruction: String, -} - -impl MemorySemanticIndexConfig { - pub fn from_env() -> Self { - Self { - qdrant_url: env_value("EPIPHANY_QDRANT_URL", "http://127.0.0.1:6333"), - qdrant_api_key: env::var("EPIPHANY_QDRANT_API_KEY") - .ok() - .filter(|value| !value.trim().is_empty()), - qdrant_timeout_ms: env_u64("EPIPHANY_QDRANT_TIMEOUT_MS", 30_000), - ollama_base_url: env_value("EPIPHANY_OLLAMA_BASE_URL", "http://127.0.0.1:11434"), - ollama_model: env_value("EPIPHANY_OLLAMA_MODEL", "qwen3-embedding:0.6b"), - ollama_timeout_ms: env_u64("EPIPHANY_OLLAMA_TIMEOUT_MS", 30_000), - embedding_provider_id: env_value( - "EPIPHANY_EMBEDDING_PROVIDER_ID", - "gamecult-ollama-embedding", - ), - modeling_collection: env_value( - "EPIPHANY_MODELING_QDRANT_COLLECTION", - MODELING_COLLECTION_DEFAULT, - ), - modeling_query_instruction: "Given a repository architecture, dataflow, ownership, invariant, or frontier question, rank the canonical Modeling documents that answer it.".to_string(), - } - } - - pub(crate) fn collection(&self) -> &str { - &self.modeling_collection - } - - fn query_instruction(&self) -> &str { - &self.modeling_query_instruction - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub(super) struct MemorySemanticPointPayload { - point_id: String, - swarm_id: String, - obligation_id: String, - claim_id: String, - claim_epoch: String, - canonical_locator: String, - canonical_type: String, - canonical_key: String, - canonical_document_id: String, - canonical_schema_version: String, - graph_id: String, - indexed_model_revision: u64, - indexed_model_hash: String, - indexed_canonical_content_hash: String, - projection_schema_version: String, - embedding_provider_id: String, - embedding_model: String, -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_projection_obligation", - schema = "MemorySemanticProjectionObligation" -)] -pub struct MemorySemanticProjectionObligation { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub obligation_id: String, - #[cultcache(key = 2)] - pub swarm_id: String, - #[cultcache(key = 3)] - pub partition: String, - #[cultcache(key = 4)] - pub canonical_source_id: String, - #[cultcache(key = 5)] - pub source_commit_id: String, - #[cultcache(key = 6)] - pub graph_id: String, - #[cultcache(key = 7)] - pub source_generation: u64, - #[cultcache(key = 8)] - pub source_model_hash: String, - #[cultcache(key = 9)] - pub canonical_content_set_hash: String, - #[cultcache(key = 10)] - pub projection_schema_version: String, - #[cultcache(key = 11)] - pub created_at: String, -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_projection_attempt", - schema = "MemorySemanticProjectionAttempt" -)] -pub struct MemorySemanticProjectionAttempt { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub attempt_id: String, - #[cultcache(key = 2)] - pub obligation_id: String, - #[cultcache(key = 3)] - pub started_at: String, - #[cultcache(key = 4)] - pub completed_at: Option, - #[cultcache(key = 5)] - pub status: String, - #[cultcache(key = 6)] - pub error: Option, - #[cultcache(key = 7)] - pub claim_id: String, - #[cultcache(key = 8)] - pub claim_epoch: u64, - #[cultcache(key = 9)] - pub executor_id: String, - #[cultcache(key = 10)] - pub executor_incarnation: String, - #[cultcache(key = 11)] - pub authority_id: String, - #[cultcache(key = 12, default)] - pub physical_backend_url: String, - #[cultcache(key = 13, default)] - pub collection_name: String, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum MemorySemanticProjectionHealthStatus { - Pending, - Failed, - Stale, - Ready, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct MemorySemanticProjectionSourceHead { - pub swarm_id: String, - pub partition: String, - pub canonical_source_id: String, - pub source_commit_id: String, - pub graph_id: String, - pub source_generation: u64, - pub source_model_hash: String, - pub canonical_content_set_hash: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct MemorySemanticProjectionHealth { - pub status: MemorySemanticProjectionHealthStatus, - pub obligation_id: String, - pub receipt_id: Option, - pub latest_attempt_id: Option, - pub latest_error: Option, - pub query_eligible: bool, -} - -#[derive(Clone, Debug)] -pub struct MemorySemanticProjectionReadiness { - pub(crate) obligation: MemorySemanticProjectionObligation, - pub(crate) current: MemorySemanticProjectionSourceHead, - pub(crate) receipt: MemorySemanticIndexReceipt, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct MemorySemanticLiveEvidence { - pub(crate) collection_name: String, - pub(crate) observed_point_count: u32, - pub(crate) observed_vector_binding_root_sha256: String, -} - -pub(super) trait MemorySemanticEvidencePort { - fn collection_exists(&mut self, name: &str) -> Result; - fn collection_compatibility(&mut self, name: &str) -> Result; - fn points_for_scope( - &mut self, - name: &str, - scope: &[(&str, &str)], - ) -> Result>>; -} - -impl MemorySemanticEvidencePort for QdrantBackend { - fn collection_exists(&mut self, name: &str) -> Result { - QdrantBackend::collection_exists(self, name) - } - fn collection_compatibility(&mut self, name: &str) -> Result { - QdrantBackend::collection_compatibility(self, name) - } - fn points_for_scope( - &mut self, - name: &str, - scope: &[(&str, &str)], - ) -> Result>> { - QdrantBackend::points_for_scope(self, name, scope) - } -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_index_receipt", - schema = "MemorySemanticIndexReceipt" -)] -pub struct MemorySemanticIndexReceipt { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub receipt_id: String, - #[cultcache(key = 2)] - pub swarm_id: String, - #[cultcache(key = 3)] - pub partition: String, - #[cultcache(key = 4)] - pub collection_name: String, - #[cultcache(key = 5)] - pub graph_id: String, - #[cultcache(key = 6)] - pub model_revision: u64, - #[cultcache(key = 7)] - pub model_hash: String, - #[cultcache(key = 8)] - pub embedding_provider_id: String, - #[cultcache(key = 9)] - pub embedding_model: String, - #[cultcache(key = 10)] - pub vector_dimensions: u32, - #[cultcache(key = 11)] - pub indexed_document_count: u32, - #[cultcache(key = 12)] - pub deleted_document_count: u32, - #[cultcache(key = 13)] - pub canonical_content_set_hash: String, - #[cultcache(key = 14)] - pub indexed_at: String, - #[cultcache(key = 15)] - pub status: String, - #[cultcache(key = 16)] - pub obligation_id: String, - #[cultcache(key = 17)] - pub canonical_source_id: String, - #[cultcache(key = 18)] - pub source_commit_id: String, - #[cultcache(key = 19)] - pub source_generation: u64, - #[cultcache(key = 20)] - pub projection_schema_version: String, - #[cultcache(key = 21, default)] - pub claim_id: String, - #[cultcache(key = 22, default)] - pub claim_epoch: u64, - #[cultcache(key = 23, default)] - pub observed_vector_binding_root_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(super) struct MemorySemanticProjectionNamespace { - pub(super) obligation_id: String, - pub(super) claim_id: String, - pub(super) claim_epoch: u64, -} - -pub fn validate_memory_semantic_projection_obligation( - obligation: &MemorySemanticProjectionObligation, -) -> Result<()> { - if obligation.schema_version != MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION { - return Err(anyhow!("unsupported semantic projection obligation schema")); - } - for (label, value) in [ - ("obligation_id", obligation.obligation_id.as_str()), - ("swarm_id", obligation.swarm_id.as_str()), - ("partition", obligation.partition.as_str()), - ( - "canonical_source_id", - obligation.canonical_source_id.as_str(), - ), - ("source_commit_id", obligation.source_commit_id.as_str()), - ("graph_id", obligation.graph_id.as_str()), - ("source_model_hash", obligation.source_model_hash.as_str()), - ( - "canonical_content_set_hash", - obligation.canonical_content_set_hash.as_str(), - ), - ("created_at", obligation.created_at.as_str()), - ] { - if value.trim().is_empty() { - return Err(anyhow!("semantic projection obligation missing {label}")); - } - } - if obligation.partition != "modeling" { - return Err(anyhow!( - "semantic projection obligation has invalid partition" - )); - } - if obligation.projection_schema_version != SEMANTIC_PROJECTION_SCHEMA_VERSION { - return Err(anyhow!("semantic projection obligation schema mismatch")); - } - Ok(()) -} - -pub fn derive_memory_semantic_projection_obligation( - snapshot: &EpiphanyMemoryGraphSnapshot, - swarm_id: &str, - canonical_source_id: &str, - source_commit_id: &str, - created_at: &str, -) -> Result { - for (label, value) in [ - ("swarm_id", swarm_id), - ("canonical_source_id", canonical_source_id), - ("source_commit_id", source_commit_id), - ("created_at", created_at), - ] { - if value.trim().is_empty() { - return Err(anyhow!("semantic projection obligation missing {label}")); - } - } - chrono::DateTime::parse_from_rfc3339(created_at) - .map_err(|_| anyhow!("semantic projection obligation timestamp must be RFC3339"))?; - let documents = derive_semantic_projection(swarm_id, snapshot)?; - let canonical_content_set_hash = canonical_content_set_hash(&documents); - let partition = MODELING_PARTITION.to_string(); - let identity = format!("{swarm_id}|{partition}|{canonical_source_id}|{source_commit_id}"); - let obligation = MemorySemanticProjectionObligation { - schema_version: MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION.to_string(), - obligation_id: format!( - "memory-semantic-projection-{partition}-{:x}", - Sha256::digest(identity.as_bytes()) - ), - swarm_id: swarm_id.to_string(), - partition, - canonical_source_id: canonical_source_id.to_string(), - source_commit_id: source_commit_id.to_string(), - graph_id: snapshot.graph_id.clone(), - source_generation: snapshot.model_revision, - source_model_hash: crate::memory_graph_model_hash(snapshot)?, - canonical_content_set_hash, - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - created_at: created_at.to_string(), - }; - validate_memory_semantic_projection_obligation(&obligation)?; - Ok(obligation) -} - -pub fn validate_memory_semantic_projection_attempt( - attempt: &MemorySemanticProjectionAttempt, -) -> Result<()> { - if attempt.schema_version != MEMORY_SEMANTIC_PROJECTION_ATTEMPT_SCHEMA_VERSION { - return Err(anyhow!("unsupported semantic projection attempt schema")); - } - if attempt.attempt_id.trim().is_empty() - || attempt.obligation_id.trim().is_empty() - || attempt.claim_id.trim().is_empty() - || attempt.claim_epoch == 0 - || attempt.executor_id.trim().is_empty() - || attempt.executor_incarnation.trim().is_empty() - || attempt.authority_id.trim().is_empty() - || attempt.started_at.trim().is_empty() - || chrono::DateTime::parse_from_rfc3339(&attempt.started_at).is_err() - || attempt - .completed_at - .as_deref() - .is_some_and(|completed_at| chrono::DateTime::parse_from_rfc3339(completed_at).is_err()) - { - return Err(anyhow!( - "semantic projection attempt is missing identity or time" - )); - } - if attempt.completed_at.as_deref().is_some_and(|completed_at| { - chrono::DateTime::parse_from_rfc3339(completed_at).ok() - < chrono::DateTime::parse_from_rfc3339(&attempt.started_at).ok() - }) { - return Err(anyhow!( - "semantic projection attempt completes before it starts" - )); - } - if attempt.physical_backend_url.trim().is_empty() != attempt.collection_name.trim().is_empty() { - return Err(anyhow!( - "semantic projection attempt has a partial physical namespace" - )); - } - match attempt.status.as_str() { - "running" if attempt.completed_at.is_none() && attempt.error.is_none() => Ok(()), - "failed" if attempt.completed_at.is_some() && attempt.error.is_some() => Ok(()), - "succeeded" if attempt.completed_at.is_some() && attempt.error.is_none() => Ok(()), - _ => Err(anyhow!( - "semantic projection attempt status does not match its terminal fields" - )), - } -} - -pub fn derive_memory_semantic_projection_health( - obligation: &MemorySemanticProjectionObligation, - current: &MemorySemanticProjectionSourceHead, - attempts: &[MemorySemanticProjectionAttempt], - receipts: &[MemorySemanticIndexReceipt], -) -> Result { - validate_memory_semantic_projection_obligation(obligation)?; - for attempt in attempts - .iter() - .filter(|attempt| attempt.obligation_id == obligation.obligation_id) - { - validate_memory_semantic_projection_attempt(attempt)?; - } - let stale = !obligation_matches_source(obligation, current); - let mut matching_receipts = receipts - .iter() - .filter(|receipt| receipt_matches_obligation(receipt, obligation)) - .collect::>(); - matching_receipts.sort_by_key(|receipt| { - chrono::DateTime::parse_from_rfc3339(&receipt.indexed_at) - .expect("matching receipt has valid RFC3339 time") - }); - let receipt = matching_receipts.last().copied(); - let mut matching_attempts = attempts - .iter() - .filter(|attempt| attempt.obligation_id == obligation.obligation_id) - .collect::>(); - matching_attempts.sort_by_key(|attempt| { - chrono::DateTime::parse_from_rfc3339( - attempt - .completed_at - .as_deref() - .unwrap_or(attempt.started_at.as_str()), - ) - .expect("validated attempt has RFC3339 ordering time") - }); - let latest_attempt = matching_attempts.last().copied(); - let repair_after_receipt = latest_attempt - .zip(receipt) - .is_some_and(|(attempt, receipt)| { - chrono::DateTime::parse_from_rfc3339(&attempt.started_at).ok() - > chrono::DateTime::parse_from_rfc3339(&receipt.indexed_at).ok() - && attempt.status != "succeeded" - }); - let status = if stale { - MemorySemanticProjectionHealthStatus::Stale - } else if repair_after_receipt - && latest_attempt.is_some_and(|attempt| attempt.status == "failed") - { - MemorySemanticProjectionHealthStatus::Failed - } else if repair_after_receipt { - MemorySemanticProjectionHealthStatus::Pending - } else if receipt.is_some() { - MemorySemanticProjectionHealthStatus::Ready - } else if latest_attempt.is_some_and(|attempt| attempt.status == "failed") { - MemorySemanticProjectionHealthStatus::Failed - } else { - MemorySemanticProjectionHealthStatus::Pending - }; - Ok(MemorySemanticProjectionHealth { - status, - obligation_id: obligation.obligation_id.clone(), - receipt_id: receipt.map(|receipt| receipt.receipt_id.clone()), - latest_attempt_id: latest_attempt.map(|attempt| attempt.attempt_id.clone()), - latest_error: latest_attempt.and_then(|attempt| attempt.error.clone()), - query_eligible: status == MemorySemanticProjectionHealthStatus::Ready - && receipt.is_some_and(|receipt| { - memory_semantic_projection_query_eligible(obligation, current, receipt) - }), - }) -} - -pub fn memory_semantic_projection_query_eligible( - obligation: &MemorySemanticProjectionObligation, - current: &MemorySemanticProjectionSourceHead, - receipt: &MemorySemanticIndexReceipt, -) -> bool { - validate_memory_semantic_projection_obligation(obligation).is_ok() - && obligation_matches_source(obligation, current) - && receipt_matches_obligation(receipt, obligation) - && receipt.vector_dimensions > 0 - && receipt.indexed_document_count > 0 -} - -pub(super) fn memory_semantic_projection_terminal_success( - obligation: &MemorySemanticProjectionObligation, - current: &MemorySemanticProjectionSourceHead, - receipt: &MemorySemanticIndexReceipt, -) -> bool { - validate_memory_semantic_projection_obligation(obligation).is_ok() - && obligation_matches_source(obligation, current) - && receipt_matches_obligation(receipt, obligation) - && ((receipt.indexed_document_count > 0 && receipt.vector_dimensions > 0) - || (receipt.indexed_document_count == 0 - && receipt.vector_dimensions == 0 - && obligation.canonical_content_set_hash == canonical_content_set_hash(&[]) - && receipt.observed_vector_binding_root_sha256 - == format!("{:x}", Sha256::digest([])))) -} - -fn is_sha256(value: &str) -> bool { - value.len() == 64 - && value - .bytes() - .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) -} - -pub fn bind_memory_semantic_index_receipt( - mut receipt: MemorySemanticIndexReceipt, - obligation: &MemorySemanticProjectionObligation, -) -> Result { - validate_memory_semantic_projection_obligation(obligation)?; - if receipt.schema_version != MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION - || !is_sha256(&receipt.observed_vector_binding_root_sha256) - || receipt.swarm_id != obligation.swarm_id - || receipt.partition != obligation.partition - || receipt.graph_id != obligation.graph_id - || receipt.model_revision != obligation.source_generation - || receipt.model_hash != obligation.source_model_hash - || receipt.canonical_content_set_hash != obligation.canonical_content_set_hash - || receipt.status != "ready" - { - return Err(anyhow!( - "semantic index result does not match the exact projection obligation" - )); - } - receipt.obligation_id = obligation.obligation_id.clone(); - receipt.canonical_source_id = obligation.canonical_source_id.clone(); - receipt.source_commit_id = obligation.source_commit_id.clone(); - receipt.source_generation = obligation.source_generation; - receipt.projection_schema_version = obligation.projection_schema_version.clone(); - Ok(receipt) -} - -fn obligation_matches_source( - obligation: &MemorySemanticProjectionObligation, - current: &MemorySemanticProjectionSourceHead, -) -> bool { - obligation.swarm_id == current.swarm_id - && obligation.partition == current.partition - && obligation.canonical_source_id == current.canonical_source_id - && obligation.source_commit_id == current.source_commit_id - && obligation.graph_id == current.graph_id - && obligation.source_generation == current.source_generation - && obligation.source_model_hash == current.source_model_hash - && obligation.canonical_content_set_hash == current.canonical_content_set_hash -} - -fn receipt_matches_obligation( - receipt: &MemorySemanticIndexReceipt, - obligation: &MemorySemanticProjectionObligation, -) -> bool { - receipt.schema_version == MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION - && receipt.status == "ready" - && receipt.obligation_id == obligation.obligation_id - && receipt.swarm_id == obligation.swarm_id - && receipt.partition == obligation.partition - && receipt.canonical_source_id == obligation.canonical_source_id - && receipt.source_commit_id == obligation.source_commit_id - && receipt.graph_id == obligation.graph_id - && receipt.source_generation == obligation.source_generation - && receipt.model_revision == obligation.source_generation - && receipt.model_hash == obligation.source_model_hash - && receipt.canonical_content_set_hash == obligation.canonical_content_set_hash - && receipt.projection_schema_version == obligation.projection_schema_version - && !receipt.claim_id.trim().is_empty() - && receipt.claim_epoch > 0 - && is_sha256(&receipt.observed_vector_binding_root_sha256) - && chrono::DateTime::parse_from_rfc3339(&receipt.indexed_at).is_ok() -} - -fn authenticate_observed_projection( - observed: Vec>, - desired: &BTreeMap, - vector_dimensions: usize, -) -> Result { - if observed.len() != desired.len() { - return Err(anyhow!( - "semantic projection live point count disagrees with canonical set" - )); - } - let mut seen = HashSet::new(); - let mut vector_bindings = Vec::with_capacity(observed.len()); - for point in observed { - if !seen.insert(point.id.clone()) { - return Err(anyhow!( - "semantic projection live scroll returned a duplicate point id" - )); - } - let expected = desired.get(&point.id).ok_or_else(|| { - anyhow!("semantic projection live scroll returned a foreign point id") - })?; - if point.payload.as_ref() != Some(expected) { - return Err(anyhow!( - "semantic projection live payload disagrees with canonical payload" - )); - } - let vector = point - .vector - .ok_or_else(|| anyhow!("semantic projection live point omitted its vector"))?; - if vector_dimensions == 0 || vector.len() != vector_dimensions { - return Err(anyhow!( - "semantic projection live vector dimensions disagree" - )); - } - if vector.iter().any(|value| !value.is_finite()) { - return Err(anyhow!( - "semantic projection live vector contains a non-finite value" - )); - } - let vector_sha256 = format!( - "{:x}", - Sha256::digest( - vector - .iter() - .flat_map(|value| value.to_le_bytes()) - .collect::>() - ) - ); - vector_bindings.push(format!("{}|{}", point.id, vector_sha256)); - } - if seen.len() != desired.len() || desired.keys().any(|id| !seen.contains(id)) { - return Err(anyhow!( - "semantic projection live IDs disagree with canonical set" - )); - } - vector_bindings.sort(); - Ok(format!( - "{:x}", - Sha256::digest(vector_bindings.join("\n").as_bytes()) - )) -} - -pub(super) fn index_memory_semantic_partition( - snapshot: &EpiphanyMemoryGraphSnapshot, - swarm_id: &str, - namespace: &MemorySemanticProjectionNamespace, - indexed_at: &str, - config: &MemorySemanticIndexConfig, -) -> Result { - let documents = derive_semantic_projection(swarm_id, snapshot)?; - let backend = qdrant(config)?; - let collection = config.collection(); - if namespace.obligation_id.trim().is_empty() - || namespace.claim_id.trim().is_empty() - || namespace.claim_epoch == 0 - { - return Err(anyhow!("semantic projection physical namespace is invalid")); - } - let claim_epoch = namespace.claim_epoch.to_string(); - let scope = [ - ("swarmId", swarm_id), - ("partition", MODELING_PARTITION), - ("obligationId", namespace.obligation_id.as_str()), - ("claimId", namespace.claim_id.as_str()), - ("claimEpoch", claim_epoch.as_str()), - ]; - let content_set_hash = canonical_content_set_hash(&documents); - let model_hash = crate::memory_graph_model_hash(snapshot)?; - - if documents.is_empty() { - let (vector_size, deleted_document_count) = if backend.collection_exists(collection)? { - let actual = backend.collection_compatibility(collection)?; - let expected = compatibility(config, actual.vector_size); - if actual != expected { - return Err(anyhow!( - "Qdrant collection {collection} is incompatible: actual {actual:?}, expected {expected:?}" - )); - } - let existing_ids = backend.point_ids_for_scope(collection, &scope)?; - backend.delete_points(collection, &existing_ids)?; - let observed_ids = backend.point_ids_for_scope(collection, &scope)?; - if !observed_ids.is_empty() { - return Err(anyhow!( - "Qdrant scope synchronization failed: expected no points, observed {observed_ids:?}" - )); - } - (actual.vector_size as u32, existing_ids.len() as u32) - } else { - // An empty projection has nothing to embed and does not justify creating - // physical projection state. Absence already represents the empty set. - (0, 0) - }; - return Ok(memory_semantic_index_receipt( - snapshot, - swarm_id, - indexed_at, - config, - collection, - &model_hash, - &content_set_hash, - vector_size, - 0, - deleted_document_count, - &format!("{:x}", Sha256::digest([])), - namespace, - )); - } - - let embedder = embedder(config)?; - let texts = documents - .iter() - .map(|document| document.projection_text.clone()) - .collect::>(); - let embeddings = embedder.embed_documents(&texts)?; - let vector_size = embeddings - .first() - .map(Vec::len) - .ok_or_else(|| anyhow!("semantic projection produced no embeddings"))?; - let compatibility = compatibility(config, vector_size); - if backend.collection_exists(collection)? { - let actual = backend.collection_compatibility(collection)?; - if actual != compatibility { - return Err(anyhow!( - "Qdrant collection {collection} is incompatible: actual {actual:?}, expected {compatibility:?}" - )); - } - } else { - backend.create_collection(collection, &compatibility)?; - } - let existing_ids = backend.point_ids_for_scope(collection, &scope)?; - let points = documents - .iter() - .zip(embeddings) - .map(|(document, vector)| SemanticPoint { - id: physical_point_id(namespace, &document.point_id), - vector, - payload: point_payload(document, config, namespace), - }) - .collect::>(); - backend.upsert_points(collection, &points)?; - let live_ids = documents - .iter() - .map(|document| physical_point_id(namespace, &document.point_id)) - .collect::>(); - let deleted_ids = existing_ids - .into_iter() - .filter(|id| !live_ids.contains(id.as_str())) - .collect::>(); - backend.delete_points(collection, &deleted_ids)?; - let observed_ids = backend.point_ids_for_scope(collection, &scope)?; - let desired_ids = documents - .iter() - .map(|document| physical_point_id(namespace, &document.point_id)) - .collect::>(); - let observed_ids = observed_ids.into_iter().collect::>(); - if observed_ids != desired_ids { - return Err(anyhow!( - "Qdrant scope synchronization failed: observed IDs do not equal the desired projection" - )); - } - let desired_payloads = documents - .iter() - .map(|document| { - ( - physical_point_id(namespace, &document.point_id), - point_payload(document, config, namespace), - ) - }) - .collect::>(); - let observed_vector_binding_root_sha256 = authenticate_observed_projection( - backend.points_for_scope::(collection, &scope)?, - &desired_payloads, - vector_size, - )?; - Ok(memory_semantic_index_receipt( - snapshot, - swarm_id, - indexed_at, - config, - collection, - &model_hash, - &content_set_hash, - vector_size as u32, - documents.len() as u32, - deleted_ids.len() as u32, - &observed_vector_binding_root_sha256, - namespace, - )) -} - -#[allow(clippy::too_many_arguments)] -fn memory_semantic_index_receipt( - snapshot: &EpiphanyMemoryGraphSnapshot, - swarm_id: &str, - indexed_at: &str, - config: &MemorySemanticIndexConfig, - collection: &str, - model_hash: &str, - content_set_hash: &str, - vector_dimensions: u32, - indexed_document_count: u32, - deleted_document_count: u32, - observed_vector_binding_root_sha256: &str, - namespace: &MemorySemanticProjectionNamespace, -) -> MemorySemanticIndexReceipt { - let receipt_id = format!( - "memory-semantic-index-{}-{}-{}-{}", - MODELING_PARTITION, - snapshot.model_revision, - &content_set_hash[..16], - &format!( - "{:x}", - Sha256::digest( - format!( - "{}|{}|{}|{}", - indexed_at, namespace.obligation_id, namespace.claim_id, namespace.claim_epoch - ) - .as_bytes() - ) - )[..12] - ); - MemorySemanticIndexReceipt { - schema_version: MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id, - swarm_id: swarm_id.to_string(), - partition: MODELING_PARTITION.to_string(), - collection_name: collection.to_string(), - graph_id: snapshot.graph_id.clone(), - model_revision: snapshot.model_revision, - model_hash: model_hash.to_string(), - embedding_provider_id: config.embedding_provider_id.clone(), - embedding_model: config.ollama_model.clone(), - vector_dimensions, - indexed_document_count, - deleted_document_count, - canonical_content_set_hash: content_set_hash.to_string(), - indexed_at: indexed_at.to_string(), - status: "ready".to_string(), - obligation_id: namespace.obligation_id.clone(), - canonical_source_id: snapshot.graph_id.clone(), - source_commit_id: String::new(), - source_generation: snapshot.model_revision, - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - claim_id: namespace.claim_id.clone(), - claim_epoch: namespace.claim_epoch, - observed_vector_binding_root_sha256: observed_vector_binding_root_sha256.to_string(), - } -} - -pub fn semantic_memory_context( - snapshot: &EpiphanyMemoryGraphSnapshot, - swarm_id: &str, - query: &EpiphanyMemoryContextQuery, - readiness: Option<&MemorySemanticProjectionReadiness>, - config: &MemorySemanticIndexConfig, -) -> EpiphanyMemoryContextPacket { - let eligible = readiness.is_some_and(|readiness| { - let source_matches_query = (|| -> Result { - let documents = derive_semantic_projection(swarm_id, snapshot)?; - Ok(readiness.obligation.swarm_id == swarm_id - && readiness.obligation.partition == MODELING_PARTITION - && readiness.obligation.graph_id == snapshot.graph_id - && readiness.obligation.source_generation == snapshot.model_revision - && readiness.obligation.source_model_hash - == crate::memory_graph_model_hash(snapshot)? - && readiness.obligation.canonical_content_set_hash - == canonical_content_set_hash(&documents)) - })() - .unwrap_or(false); - source_matches_query - && memory_semantic_projection_query_eligible( - &readiness.obligation, - &readiness.current, - &readiness.receipt, - ) - }); - if !eligible { - let mut packet = plan_modeling_context_cut(snapshot, query, &[]); - packet.warnings.push( - "semantic projection unavailable; used canonical BM25 fallback: newest canonical obligation has no exact success receipt" - .to_string(), - ); - return packet; - } - let readiness = readiness.expect("eligible semantic readiness disappeared"); - match try_semantic_memory_context(snapshot, swarm_id, query, readiness, config) { - Ok(packet) => packet, - Err(error) => { - let mut packet = plan_modeling_context_cut(snapshot, query, &[]); - packet.warnings.push(format!( - "semantic projection unavailable; used canonical BM25 fallback: {error}" - )); - packet - } - } -} - -fn try_semantic_memory_context( - snapshot: &EpiphanyMemoryGraphSnapshot, - swarm_id: &str, - query: &EpiphanyMemoryContextQuery, - readiness: &MemorySemanticProjectionReadiness, - config: &MemorySemanticIndexConfig, -) -> Result { - let text = query - .text - .as_deref() - .filter(|text| !text.trim().is_empty()) - .ok_or_else(|| anyhow!("semantic context requires query text"))?; - let documents = derive_semantic_projection(swarm_id, snapshot)?; - let backend = qdrant(config)?; - let collection = config.collection(); - if !backend.collection_exists(collection)? { - return Err(anyhow!("semantic collection {collection} is missing")); - } - let embedder = embedder(config)?; - let vector = embedder.embed_query(text)?; - let expected = compatibility(config, vector.len()); - let actual = backend.collection_compatibility(collection)?; - if actual != expected { - return Err(anyhow!("semantic collection compatibility mismatch")); - } - let limit = query.budget.unwrap_or(12).clamp(1, QUERY_LIMIT_MAX as u32) as usize; - let query_claim_epoch = readiness.receipt.claim_epoch.to_string(); - let ranked = backend.query_points_for_scope::( - collection, - &vector, - limit, - &[ - ("swarmId", swarm_id), - ("partition", MODELING_PARTITION), - ("obligationId", readiness.receipt.obligation_id.as_str()), - ("claimId", readiness.receipt.claim_id.as_str()), - ("claimEpoch", query_claim_epoch.as_str()), - ], - )?; - let mut ranked_ids = Vec::new(); - for hit in ranked { - let payload = hit - .payload - .ok_or_else(|| anyhow!("semantic candidate omitted its typed locator payload"))?; - if payload.swarm_id != swarm_id - || payload.obligation_id != readiness.receipt.obligation_id - || payload.claim_id != readiness.receipt.claim_id - || payload.claim_epoch != readiness.receipt.claim_epoch.to_string() - || payload.embedding_provider_id != config.embedding_provider_id - || payload.embedding_model != config.ollama_model - || payload.projection_schema_version != SEMANTIC_PROJECTION_SCHEMA_VERSION - { - continue; - } - let candidate = SemanticProjectionCandidate { - point_id: payload.point_id, - canonical: super::SemanticCanonicalLocator { - locator: payload.canonical_locator, - canonical_type: payload.canonical_type, - canonical_key: payload.canonical_key, - canonical_document_id: payload.canonical_document_id, - }, - score: hit.score, - indexed_model_revision: payload.indexed_model_revision, - indexed_model_hash: payload.indexed_model_hash, - indexed_canonical_content_hash: payload.indexed_canonical_content_hash, - }; - if let Ok(document) = resolve_semantic_candidate(&candidate, &documents) { - ranked_ids.push(document.canonical.canonical_document_id.clone()); - } - } - let mut packet = plan_modeling_context_cut(snapshot, query, &ranked_ids); - packet.warnings.push(format!( - "semantic projection ranked {} canonical {} candidates; all payload text was ignored", - ranked_ids.len(), - MODELING_PARTITION - )); - Ok(packet) -} - -pub(super) fn point_payload( - document: &SemanticProjectionDocument, - config: &MemorySemanticIndexConfig, - namespace: &MemorySemanticProjectionNamespace, -) -> MemorySemanticPointPayload { - MemorySemanticPointPayload { - point_id: document.point_id.clone(), - swarm_id: document.swarm_id.clone(), - obligation_id: namespace.obligation_id.clone(), - claim_id: namespace.claim_id.clone(), - claim_epoch: namespace.claim_epoch.to_string(), - canonical_locator: document.canonical.locator.clone(), - canonical_type: document.canonical.canonical_type.clone(), - canonical_key: document.canonical.canonical_key.clone(), - canonical_document_id: document.canonical.canonical_document_id.clone(), - canonical_schema_version: document.canonical_schema_version.clone(), - graph_id: document.graph_id.clone(), - indexed_model_revision: document.model_revision, - indexed_model_hash: document.model_hash.clone(), - indexed_canonical_content_hash: document.canonical_content_hash.clone(), - projection_schema_version: document.projection_schema_version.clone(), - embedding_provider_id: config.embedding_provider_id.clone(), - embedding_model: config.ollama_model.clone(), - } -} - -pub(super) fn physical_point_id( - namespace: &MemorySemanticProjectionNamespace, - canonical_point_id: &str, -) -> String { - Uuid::new_v5( - &Uuid::NAMESPACE_URL, - format!( - "{}|{}|{}|{}", - namespace.obligation_id, namespace.claim_id, namespace.claim_epoch, canonical_point_id - ) - .as_bytes(), - ) - .to_string() -} - -fn qdrant(config: &MemorySemanticIndexConfig) -> Result { - QdrantBackend::new(QdrantConfig { - url: config.qdrant_url.clone(), - api_key: config.qdrant_api_key.clone(), - timeout_ms: config.qdrant_timeout_ms, - }) -} - -#[allow(dead_code)] // Consumed by the repository-readiness join in the next bounded cut. -pub(crate) fn observe_memory_semantic_live_evidence( - store_path: &Path, - config: &MemorySemanticIndexConfig, - input: &super::MemorySemanticProjectionInput, - readiness: &MemorySemanticProjectionReadiness, -) -> Result> { - let mut backend = qdrant(config)?; - observe_memory_semantic_live_evidence_with_port( - store_path, - config, - input, - readiness, - &mut backend, - ) -} - -pub(super) fn observe_memory_semantic_live_evidence_with_port( - store_path: &Path, - config: &MemorySemanticIndexConfig, - input: &super::MemorySemanticProjectionInput, - readiness: &MemorySemanticProjectionReadiness, - port: &mut impl MemorySemanticEvidencePort, -) -> Result> { - let store_path = store_path.to_path_buf(); - observe_memory_semantic_live_evidence_with(config, input, readiness, port, || { - semantic_authority_still_exact(&store_path, input, readiness) - }) -} - -fn observe_memory_semantic_live_evidence_with( - config: &MemorySemanticIndexConfig, - input: &super::MemorySemanticProjectionInput, - readiness: &MemorySemanticProjectionReadiness, - port: &mut impl MemorySemanticEvidencePort, - mut authority_still_exact: impl FnMut() -> Result, -) -> Result> { - if readiness.obligation != input.obligation - || readiness.current != input.authority.head - || !receipt_matches_obligation(&readiness.receipt, &input.obligation) - { - return Ok(None); - } - if input.obligation.partition != MODELING_PARTITION - || readiness.receipt.collection_name != config.collection() - { - return Ok(None); - } - let documents = derive_semantic_projection(&input.obligation.swarm_id, &input.snapshot)?; - if documents.len() as u32 != readiness.receipt.indexed_document_count - || canonical_content_set_hash(&documents) != readiness.receipt.canonical_content_set_hash - || readiness.receipt.embedding_provider_id != config.embedding_provider_id - || readiness.receipt.embedding_model != config.ollama_model - || readiness.receipt.vector_dimensions == 0 - { - return Ok(None); - } - if !authority_still_exact()? { - return Ok(None); - } - let collection = readiness.receipt.collection_name.as_str(); - if !port.collection_exists(collection)? - || port.collection_compatibility(collection)? - != compatibility(config, readiness.receipt.vector_dimensions as usize) - { - return Ok(None); - } - let namespace = MemorySemanticProjectionNamespace { - obligation_id: readiness.receipt.obligation_id.clone(), - claim_id: readiness.receipt.claim_id.clone(), - claim_epoch: readiness.receipt.claim_epoch, - }; - let epoch = namespace.claim_epoch.to_string(); - let scope = [ - ("swarmId", input.obligation.swarm_id.as_str()), - ("partition", input.obligation.partition.as_str()), - ("obligationId", namespace.obligation_id.as_str()), - ("claimId", namespace.claim_id.as_str()), - ("claimEpoch", epoch.as_str()), - ]; - let desired = documents - .iter() - .map(|document| { - ( - physical_point_id(&namespace, &document.point_id), - point_payload(document, config, &namespace), - ) - }) - .collect::>(); - let observed = port.points_for_scope(collection, &scope)?; - let count = observed.len() as u32; - let root = authenticate_observed_projection( - observed, - &desired, - readiness.receipt.vector_dimensions as usize, - )?; - if root != readiness.receipt.observed_vector_binding_root_sha256 || !authority_still_exact()? { - return Ok(None); - } - Ok(Some(MemorySemanticLiveEvidence { - collection_name: collection.to_string(), - observed_point_count: count, - observed_vector_binding_root_sha256: root, - })) -} - -#[allow(dead_code)] // Production half of the bounded live-evidence reader. -fn semantic_authority_still_exact( - store_path: &Path, - input: &super::MemorySemanticProjectionInput, - expected: &MemorySemanticProjectionReadiness, -) -> Result { - let envelopes = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - if input.authority.envelopes.is_empty() - || input.authority.envelopes.iter().any(|expected| { - envelopes - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(expected) - }) - { - return Ok(false); - } - let current = super::load_memory_semantic_projection_readiness(store_path, input)?; - Ok(current.is_some_and(|current| { - current.obligation == expected.obligation - && current.current == expected.current - && current.receipt == expected.receipt - })) -} - -fn embedder(config: &MemorySemanticIndexConfig) -> Result { - OllamaEmbedder::new(OllamaConfig { - base_url: config.ollama_base_url.clone(), - model: config.ollama_model.clone(), - timeout_ms: config.ollama_timeout_ms, - query_instruction: config.query_instruction().to_string(), - }) -} - -fn compatibility( - config: &MemorySemanticIndexConfig, - vector_size: usize, -) -> CollectionCompatibility { - CollectionCompatibility { - managed_by: "epiphany".to_string(), - corpus_kind: MODELING_PARTITION.to_string(), - schema_version: 1, - projection_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - embedding_provider_id: config.embedding_provider_id.clone(), - embedding_model: config.ollama_model.clone(), - vector_size, - } -} - -fn canonical_content_set_hash(documents: &[SemanticProjectionDocument]) -> String { - let mut values = documents - .iter() - .map(|document| format!("{}:{}", document.point_id, document.canonical_content_hash)) - .collect::>(); - values.sort(); - format!("{:x}", Sha256::digest(values.join("\n").as_bytes())) -} - -fn env_value(name: &str, default: &str) -> String { - env::var(name) - .ok() - .filter(|value| !value.trim().is_empty()) - .unwrap_or_else(|| default.to_string()) -} - -fn env_u64(name: &str, default: u64) -> u64 { - env::var(name) - .ok() - .and_then(|value| value.parse().ok()) - .unwrap_or(default) -} -#[cfg(test)] -mod tests { - use super::*; - use crate::memory_graph::{ - EpiphanyMemoryDomain, EpiphanyMemoryLifecycle, EpiphanyMemoryNode, EpiphanyMemoryNodeKind, - EpiphanyMemoryProfile, MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION, memory_graph_model_hash, - }; - use tokio::runtime::Runtime; - use wiremock::matchers::{method, path}; - use wiremock::{Mock, MockServer, ResponseTemplate}; - - fn snapshot() -> EpiphanyMemoryGraphSnapshot { - let mut snapshot = EpiphanyMemoryGraphSnapshot { - schema_version: Some(MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION.to_string()), - graph_id: "semantic-fallback".to_string(), - model_revision: 3, - domains: vec![EpiphanyMemoryDomain { - id: "repo".to_string(), - profile: EpiphanyMemoryProfile::RepoArchitecture, - title: "Repository".to_string(), - lifecycle: EpiphanyMemoryLifecycle::Accepted, - ..Default::default() - }], - nodes: vec![EpiphanyMemoryNode { - id: "canonical-node".to_string(), - domain_id: "repo".to_string(), - profile: EpiphanyMemoryProfile::RepoArchitecture, - kind: EpiphanyMemoryNodeKind::Module, - title: "Semantic projection".to_string(), - claim: "Canonical graph remains correct without Qdrant.".to_string(), - question: "How is semantic recall ranked?".to_string(), - tension: "The vector service may be absent.".to_string(), - action_implication: "Fall back to typed BM25 traversal.".to_string(), - source_hashes: vec!["anchor:missing".to_string()], - lifecycle: EpiphanyMemoryLifecycle::Accepted, - confidence: 90, - ..Default::default() - }], - ..Default::default() - }; - snapshot.model_hash = memory_graph_model_hash(&snapshot).unwrap(); - snapshot - } - - #[test] - fn empty_partition_bypasses_ollama_and_does_not_create_collection() -> Result<()> { - let runtime = Runtime::new()?; - let qdrant = runtime.block_on(MockServer::start()); - runtime.block_on( - Mock::given(method("GET")) - .and(path("/collections/empty_modeling/exists")) - .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ - "result": { "exists": false }, - "status": "ok", - "time": 0.0 - }))) - .expect(1) - .mount(&qdrant), - ); - let mut empty = EpiphanyMemoryGraphSnapshot { - schema_version: Some(MEMORY_GRAPH_PROJECTION_SCHEMA_VERSION.to_string()), - graph_id: "empty-semantic-source".to_string(), - model_revision: 9, - ..Default::default() - }; - empty.model_hash = memory_graph_model_hash(&empty)?; - let mut config = MemorySemanticIndexConfig::from_env(); - config.qdrant_url = qdrant.uri(); - config.modeling_collection = "empty_modeling".to_string(); - config.ollama_base_url = "http://127.0.0.1:1".to_string(); - config.ollama_timeout_ms = 5; - - let obligation = derive_memory_semantic_projection_obligation( - &empty, - "swarm-empty", - "source-empty", - "commit-empty", - "2026-07-15T11:59:00Z", - )?; - - let receipt = index_memory_semantic_partition( - &empty, - "swarm-empty", - &MemorySemanticProjectionNamespace { - obligation_id: obligation.obligation_id.clone(), - claim_id: "claim-empty".to_string(), - claim_epoch: 1, - }, - "2026-07-15T12:00:00Z", - &config, - )?; - - assert_eq!(receipt.indexed_document_count, 0); - assert_eq!(receipt.deleted_document_count, 0); - assert_eq!(receipt.vector_dimensions, 0); - assert_eq!(receipt.model_hash, empty.model_hash); - assert_eq!(receipt.status, "ready"); - let bound = bind_memory_semantic_index_receipt(receipt, &obligation)?; - let current = MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }; - assert!(!memory_semantic_projection_query_eligible( - &obligation, - ¤t, - &bound - )); - let health = - derive_memory_semantic_projection_health(&obligation, ¤t, &[], &[bound])?; - assert_eq!(health.status, MemorySemanticProjectionHealthStatus::Ready); - assert!(!health.query_eligible); - Ok(()) - } - - #[test] - fn projection_obligation_identity_is_commit_owned_and_deterministic() -> Result<()> { - let snapshot = snapshot(); - let first = derive_memory_semantic_projection_obligation( - &snapshot, - "swarm-a", - "epiphany.runtime/runtime-a/repo-model", - "repo-model-admission-1", - "2026-07-15T00:00:00Z", - )?; - assert_eq!( - derive_memory_semantic_projection_obligation( - &snapshot, - "swarm-a", - "epiphany.runtime/runtime-a/repo-model", - "repo-model-admission-1", - "2026-07-15T00:00:00Z", - )?, - first - ); - let second = derive_memory_semantic_projection_obligation( - &snapshot, - "swarm-a", - "epiphany.runtime/runtime-a/repo-model", - "repo-model-admission-2", - "2026-07-15T00:00:01Z", - )?; - assert_ne!(first.obligation_id, second.obligation_id); - Ok(()) - } - - #[test] - fn unavailable_vector_service_preserves_canonical_bm25_packet() { - let snapshot = snapshot(); - let query = EpiphanyMemoryContextQuery { - id: "fallback-query".to_string(), - profile: Some(EpiphanyMemoryProfile::RepoArchitecture), - text: Some("canonical qdrant semantic".to_string()), - ..Default::default() - }; - let expected = plan_modeling_context_cut(&snapshot, &query, &[]); - let mut config = MemorySemanticIndexConfig::from_env(); - config.qdrant_url = "http://127.0.0.1:1".to_string(); - config.qdrant_timeout_ms = 25; - let actual = semantic_memory_context(&snapshot, "swarm", &query, None, &config); - assert_eq!(actual.nodes, expected.nodes); - assert_eq!(actual.edges, expected.edges); - assert_eq!(actual.summaries, expected.summaries); - assert!( - actual - .warnings - .iter() - .any(|warning| warning.contains("canonical BM25 fallback")) - ); - } - - #[test] - fn exact_readiness_for_one_source_cannot_open_another_query_scope() -> Result<()> { - let snapshot = snapshot(); - let obligation = derive_memory_semantic_projection_obligation( - &snapshot, - "swarm-a", - "runtime/repo-model", - "admission-current", - "2026-07-15T10:00:00Z", - )?; - let current = MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }; - let receipt = MemorySemanticIndexReceipt { - schema_version: MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id: "ready-current".to_string(), - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - collection_name: "modeling".to_string(), - graph_id: obligation.graph_id.clone(), - model_revision: obligation.source_generation, - model_hash: obligation.source_model_hash.clone(), - embedding_provider_id: "provider".to_string(), - embedding_model: "model".to_string(), - vector_dimensions: 3, - indexed_document_count: 3, - deleted_document_count: 0, - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - indexed_at: "2026-07-15T10:01:00Z".to_string(), - status: "ready".to_string(), - obligation_id: obligation.obligation_id.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - source_generation: obligation.source_generation, - projection_schema_version: obligation.projection_schema_version.clone(), - claim_id: "claim-current".to_string(), - claim_epoch: 1, - observed_vector_binding_root_sha256: "0".repeat(64), - }; - let query = EpiphanyMemoryContextQuery { - id: "swapped-source".to_string(), - text: Some("authority".to_string()), - ..Default::default() - }; - let mut config = MemorySemanticIndexConfig::from_env(); - config.qdrant_url = "http://127.0.0.1:1".to_string(); - config.ollama_base_url = "http://127.0.0.1:1".to_string(); - let readiness = MemorySemanticProjectionReadiness { - obligation: obligation.clone(), - current: current.clone(), - receipt: receipt.clone(), - }; - let packet = - semantic_memory_context(&snapshot, "swarm-b", &query, Some(&readiness), &config); - assert!(packet.warnings.iter().any(|warning| { - warning.contains("newest canonical obligation has no exact success receipt") - })); - Ok(()) - } - - #[test] - fn physical_point_identity_is_claim_epoch_isolated_while_locator_stays_canonical() { - let document = derive_semantic_projection("swarm-a", &snapshot()) - .unwrap() - .into_iter() - .next() - .expect("semantic document"); - let first = MemorySemanticProjectionNamespace { - obligation_id: "obligation-a".to_string(), - claim_id: "claim-a".to_string(), - claim_epoch: 1, - }; - let fenced = MemorySemanticProjectionNamespace { - claim_id: "claim-b".to_string(), - claim_epoch: 2, - ..first.clone() - }; - let first_id = physical_point_id(&first, &document.point_id); - let fenced_id = physical_point_id(&fenced, &document.point_id); - assert_ne!(first_id, fenced_id); - assert!(Uuid::parse_str(&first_id).is_ok()); - assert!(Uuid::parse_str(&fenced_id).is_ok()); - - let payload = point_payload(&document, &MemorySemanticIndexConfig::from_env(), &fenced); - assert_eq!(payload.point_id, document.point_id); - assert_eq!(payload.obligation_id, fenced.obligation_id); - assert_eq!(payload.claim_id, fenced.claim_id); - assert_eq!(payload.claim_epoch, fenced.claim_epoch.to_string()); - } - - #[test] - fn pre_namespace_receipt_is_never_query_eligible() { - let obligation = obligation(); - let current = source_head(); - let mut legacy = receipt(); - legacy.schema_version = "gamecult.epiphany.memory_semantic_index_receipt.v0".to_string(); - legacy.claim_id.clear(); - legacy.claim_epoch = 0; - assert!(!memory_semantic_projection_query_eligible( - &obligation, - ¤t, - &legacy - )); - } - - fn obligation() -> MemorySemanticProjectionObligation { - MemorySemanticProjectionObligation { - schema_version: MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION.to_string(), - obligation_id: "projection:swarm:modeling:commit-7".to_string(), - swarm_id: "swarm".to_string(), - partition: "modeling".to_string(), - canonical_source_id: "runtime-spine".to_string(), - source_commit_id: "commit-7".to_string(), - graph_id: "graph".to_string(), - source_generation: 7, - source_model_hash: "model-hash".to_string(), - canonical_content_set_hash: "content-hash".to_string(), - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - created_at: "2026-07-15T10:00:00Z".to_string(), - } - } - - fn source_head() -> MemorySemanticProjectionSourceHead { - let obligation = obligation(); - MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id, - partition: obligation.partition, - canonical_source_id: obligation.canonical_source_id, - source_commit_id: obligation.source_commit_id, - graph_id: obligation.graph_id, - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash, - canonical_content_set_hash: obligation.canonical_content_set_hash, - } - } - - fn receipt() -> MemorySemanticIndexReceipt { - let obligation = obligation(); - MemorySemanticIndexReceipt { - schema_version: MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id: "receipt-7".to_string(), - swarm_id: obligation.swarm_id, - partition: obligation.partition, - collection_name: "epiphany_modeling_v1".to_string(), - graph_id: obligation.graph_id, - model_revision: obligation.source_generation, - model_hash: obligation.source_model_hash, - embedding_provider_id: "provider".to_string(), - embedding_model: "model".to_string(), - vector_dimensions: 1024, - indexed_document_count: 3, - deleted_document_count: 0, - canonical_content_set_hash: obligation.canonical_content_set_hash, - indexed_at: "2026-07-15T10:01:00Z".to_string(), - status: "ready".to_string(), - obligation_id: obligation.obligation_id, - canonical_source_id: obligation.canonical_source_id, - source_commit_id: obligation.source_commit_id, - source_generation: obligation.source_generation, - projection_schema_version: obligation.projection_schema_version, - claim_id: "claim-7".to_string(), - claim_epoch: 1, - observed_vector_binding_root_sha256: "0".repeat(64), - } - } - - fn failed_attempt() -> MemorySemanticProjectionAttempt { - MemorySemanticProjectionAttempt { - schema_version: MEMORY_SEMANTIC_PROJECTION_ATTEMPT_SCHEMA_VERSION.to_string(), - attempt_id: "attempt-1".to_string(), - obligation_id: obligation().obligation_id, - started_at: "2026-07-15T10:00:30Z".to_string(), - completed_at: Some("2026-07-15T10:00:31Z".to_string()), - status: "failed".to_string(), - error: Some("qdrant unavailable".to_string()), - claim_id: "claim-7".to_string(), - claim_epoch: 1, - executor_id: "executor-a".to_string(), - executor_incarnation: "executor-a-incarnation".to_string(), - authority_id: "authority-a".to_string(), - physical_backend_url: "http://qdrant".to_string(), - collection_name: "epiphany_modeling_v1".to_string(), - } - } - - #[test] - fn projection_health_is_derived_from_exact_canonical_causality() { - let obligation = obligation(); - let current = source_head(); - let pending = - derive_memory_semantic_projection_health(&obligation, ¤t, &[], &[]).unwrap(); - assert_eq!( - pending.status, - MemorySemanticProjectionHealthStatus::Pending - ); - assert!(!pending.query_eligible); - - let failed = derive_memory_semantic_projection_health( - &obligation, - ¤t, - &[failed_attempt()], - &[], - ) - .unwrap(); - assert_eq!(failed.status, MemorySemanticProjectionHealthStatus::Failed); - assert_eq!(failed.latest_error.as_deref(), Some("qdrant unavailable")); - - let ready = derive_memory_semantic_projection_health( - &obligation, - ¤t, - &[failed_attempt()], - &[receipt()], - ) - .unwrap(); - assert_eq!(ready.status, MemorySemanticProjectionHealthStatus::Ready); - assert!(ready.query_eligible); - - let mut repair = failed_attempt(); - repair.attempt_id = "attempt-repair".to_string(); - repair.started_at = "2026-07-15T10:02:00Z".to_string(); - repair.completed_at = Some("2026-07-15T10:02:01Z".to_string()); - let repairing = derive_memory_semantic_projection_health( - &obligation, - ¤t, - &[repair], - &[receipt()], - ) - .unwrap(); - assert_eq!( - repairing.status, - MemorySemanticProjectionHealthStatus::Failed - ); - assert!(!repairing.query_eligible); - - let mut newer = current.clone(); - newer.source_generation += 1; - newer.source_commit_id = "commit-8".to_string(); - let stale = derive_memory_semantic_projection_health( - &obligation, - &newer, - &[failed_attempt()], - &[receipt()], - ) - .unwrap(); - assert_eq!(stale.status, MemorySemanticProjectionHealthStatus::Stale); - assert!(!stale.query_eligible); - } - - #[test] - fn hostile_receipt_mismatches_never_grant_query_eligibility() { - let obligation = obligation(); - let current = source_head(); - for field in [ - "obligation", - "swarm", - "partition", - "source", - "commit", - "graph", - "generation", - "revision", - "model", - "content", - "projection-schema", - "status", - "schema", - "vector-root", - "uppercase-vector-root", - "short-vector-root", - ] { - let mut hostile = receipt(); - match field { - "obligation" => hostile.obligation_id = "other".to_string(), - "swarm" => hostile.swarm_id = "other".to_string(), - "partition" => hostile.partition = "mind".to_string(), - "source" => hostile.canonical_source_id = "other".to_string(), - "commit" => hostile.source_commit_id = "other".to_string(), - "graph" => hostile.graph_id = "other".to_string(), - "generation" => hostile.source_generation += 1, - "revision" => hostile.model_revision += 1, - "model" => hostile.model_hash = "other".to_string(), - "content" => hostile.canonical_content_set_hash = "other".to_string(), - "projection-schema" => hostile.projection_schema_version = "other".to_string(), - "status" => hostile.status = "failed".to_string(), - "schema" => { - hostile.schema_version = - "gamecult.epiphany.memory_semantic_index_receipt.v1".to_string() - } - "vector-root" => hostile.observed_vector_binding_root_sha256.clear(), - "uppercase-vector-root" => { - hostile.observed_vector_binding_root_sha256 = "A".repeat(64) - } - "short-vector-root" => hostile.observed_vector_binding_root_sha256 = "0".repeat(63), - _ => unreachable!(), - } - assert!( - !memory_semantic_projection_query_eligible(&obligation, ¤t, &hostile), - "hostile {field} substitution was accepted" - ); - } - } - - #[test] - fn unbound_index_result_is_not_ready_until_exact_obligation_binding() { - let obligation = obligation(); - let current = source_head(); - let mut result = receipt(); - result.obligation_id.clear(); - result.canonical_source_id.clear(); - result.source_commit_id.clear(); - assert!(!memory_semantic_projection_query_eligible( - &obligation, - ¤t, - &result - )); - let bound = bind_memory_semantic_index_receipt(result, &obligation).unwrap(); - assert!(memory_semantic_projection_query_eligible( - &obligation, - ¤t, - &bound - )); - } - - #[test] - fn v1_and_default_vector_roots_cannot_bind_as_terminal_success() { - let obligation = obligation(); - let mut v1 = receipt(); - v1.schema_version = "gamecult.epiphany.memory_semantic_index_receipt.v1".to_string(); - assert!(bind_memory_semantic_index_receipt(v1, &obligation).is_err()); - let mut default_root = receipt(); - default_root.observed_vector_binding_root_sha256.clear(); - assert!(bind_memory_semantic_index_receipt(default_root, &obligation).is_err()); - } - - #[test] - fn zero_count_receipt_cannot_emptywash_a_nonempty_obligation() { - let obligation = obligation(); - assert_ne!( - obligation.canonical_content_set_hash, - canonical_content_set_hash(&[]) - ); - let current = source_head(); - let mut hostile = receipt(); - hostile.indexed_document_count = 0; - hostile.vector_dimensions = 0; - hostile.observed_vector_binding_root_sha256 = format!("{:x}", Sha256::digest([])); - assert!(receipt_matches_obligation(&hostile, &obligation)); - assert!(!memory_semantic_projection_terminal_success( - &obligation, - ¤t, - &hostile, - )); - } - - fn observed_payload(id: &str) -> MemorySemanticPointPayload { - MemorySemanticPointPayload { - point_id: id.to_string(), - swarm_id: "swarm-a".to_string(), - obligation_id: "obligation-a".to_string(), - claim_id: "claim-a".to_string(), - claim_epoch: "1".to_string(), - canonical_locator: format!("locator:{id}"), - canonical_type: "node".to_string(), - canonical_key: id.to_string(), - canonical_document_id: id.to_string(), - canonical_schema_version: "v0".to_string(), - graph_id: "graph-a".to_string(), - indexed_model_revision: 1, - indexed_model_hash: "model-a".to_string(), - indexed_canonical_content_hash: "content-a".to_string(), - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - embedding_provider_id: "provider".to_string(), - embedding_model: "model".to_string(), - } - } - - fn stored( - id: &str, - payload: MemorySemanticPointPayload, - vector: Option>, - ) -> crate::semantic_backend::SemanticStoredPoint { - crate::semantic_backend::SemanticStoredPoint { - id: id.to_string(), - payload: Some(payload), - vector, - } - } - - #[test] - fn observed_projection_authentication_rejects_every_live_substitution_shape() { - let desired = BTreeMap::from([ - ("a".to_string(), observed_payload("a")), - ("b".to_string(), observed_payload("b")), - ]); - let valid = vec![ - stored("a", observed_payload("a"), Some(vec![1.0, 2.0])), - stored("b", observed_payload("b"), Some(vec![3.0, 4.0])), - ]; - let root = authenticate_observed_projection(valid.clone(), &desired, 2).unwrap(); - assert!(!root.is_empty()); - - let mut cases = Vec::new(); - cases.push(vec![valid[0].clone()]); // missing - cases.push(vec![ - valid[0].clone(), - valid[1].clone(), - stored("x", observed_payload("x"), Some(vec![1.0, 2.0])), - ]); // extra - cases.push(vec![valid[0].clone(), valid[0].clone()]); // duplicate plus missing - let mut wrong_id = valid.clone(); - wrong_id[1].id = "x".to_string(); - cases.push(wrong_id); - let mut wrong_payload = valid.clone(); - wrong_payload[1].payload = Some(observed_payload("x")); - cases.push(wrong_payload); - let mut absent_vector = valid.clone(); - absent_vector[1].vector = None; - cases.push(absent_vector); - let mut wrong_dimension = valid.clone(); - wrong_dimension[1].vector = Some(vec![1.0]); - cases.push(wrong_dimension); - let mut nonfinite = valid.clone(); - nonfinite[1].vector = Some(vec![f32::NAN, 1.0]); - cases.push(nonfinite); - for hostile in cases { - assert!(authenticate_observed_projection(hostile, &desired, 2).is_err()); - } - - let mut substituted = valid; - substituted[1].vector = Some(vec![30.0, 40.0]); - assert_ne!( - authenticate_observed_projection(substituted, &desired, 2).unwrap(), - root - ); - } -} diff --git a/epiphany-core/src/memory_graph/semantic_projection.rs b/epiphany-core/src/memory_graph/semantic_projection.rs deleted file mode 100644 index 2469ac94..00000000 --- a/epiphany-core/src/memory_graph/semantic_projection.rs +++ /dev/null @@ -1,686 +0,0 @@ -use super::{ - EpiphanyMemoryDomain, EpiphanyMemoryFreshnessStatus, EpiphanyMemoryGraphSnapshot, - EpiphanyMemoryLifecycle, EpiphanyMemoryProfile, RepoFrontierStatus, memory_graph_model_hash, - validate_memory_graph_snapshot, -}; -use anyhow::{Result, anyhow}; -use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use std::collections::{HashMap, HashSet}; -use uuid::Uuid; - -pub const SEMANTIC_PROJECTION_SCHEMA_VERSION: &str = "gamecult.epiphany.semantic_projection.v0"; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum SemanticDocumentKind { - Node, - Edge, - Summary, - Frontier, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum SemanticVisibility { - PrivateVerse, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(tag = "owner", content = "value", rename_all = "snake_case")] -pub enum SemanticLifecycle { - Memory(EpiphanyMemoryLifecycle), - Frontier(RepoFrontierStatus), - Derived, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct SemanticCanonicalLocator { - pub locator: String, - pub canonical_type: String, - pub canonical_key: String, - pub canonical_document_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct SemanticProjectionDocument { - pub point_id: String, - pub swarm_id: String, - pub kind: SemanticDocumentKind, - pub canonical: SemanticCanonicalLocator, - pub graph_id: String, - pub model_revision: u64, - pub model_hash: String, - pub domain_id: String, - pub profile: EpiphanyMemoryProfile, - pub lifecycle: SemanticLifecycle, - pub visibility: SemanticVisibility, - pub source_refs: Vec, - pub source_hashes: Vec, - pub canonical_content_hash: String, - pub canonical_schema_version: String, - pub projection_schema_version: String, - pub projection_text: String, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SemanticProjectionCandidate { - pub point_id: String, - pub canonical: SemanticCanonicalLocator, - pub score: f32, - pub indexed_model_revision: u64, - pub indexed_model_hash: String, - pub indexed_canonical_content_hash: String, -} - -pub fn semantic_point_id( - swarm_id: &str, - canonical_type: &str, - canonical_key: &str, - canonical_document_id: &str, -) -> String { - Uuid::new_v5( - &Uuid::NAMESPACE_URL, - format!("{swarm_id}|modeling|{canonical_type}|{canonical_key}|{canonical_document_id}") - .as_bytes(), - ) - .to_string() -} - -pub fn derive_semantic_projection( - swarm_id: &str, - snapshot: &EpiphanyMemoryGraphSnapshot, -) -> Result> { - if swarm_id.trim().is_empty() { - return Err(anyhow!("semantic projection requires swarm_id")); - } - let validation = validate_memory_graph_snapshot(snapshot); - if !validation.is_empty() { - return Err(anyhow!("memory graph is invalid: {validation:?}")); - } - let computed_hash = memory_graph_model_hash(snapshot)?; - if !snapshot.model_hash.is_empty() && snapshot.model_hash != computed_hash { - return Err(anyhow!( - "memory graph model_hash does not match canonical content" - )); - } - let mut canonical_snapshot = snapshot.clone(); - canonical_snapshot.model_hash = computed_hash; - let snapshot = &canonical_snapshot; - - let domains = snapshot - .domains - .iter() - .map(|domain| (domain.id.as_str(), domain)) - .collect::>(); - let nodes = snapshot - .nodes - .iter() - .map(|node| (node.id.as_str(), node)) - .collect::>(); - let stale_nodes: HashSet<&str> = snapshot - .freshness - .as_ref() - .map(|freshness| { - freshness - .stale_node_ids - .iter() - .map(String::as_str) - .collect() - }) - .unwrap_or_default(); - let stale_edges: HashSet<&str> = snapshot - .freshness - .as_ref() - .map(|freshness| { - freshness - .stale_edge_ids - .iter() - .map(String::as_str) - .collect() - }) - .unwrap_or_default(); - let stale_summaries: HashSet<&str> = snapshot - .freshness - .as_ref() - .map(|freshness| { - freshness - .stale_summary_ids - .iter() - .map(String::as_str) - .collect() - }) - .unwrap_or_default(); - let mut out = Vec::new(); - - for node in &snapshot.nodes { - if !is_modeling_profile(node.profile) - || excluded_lifecycle(node.lifecycle) - || stale_nodes.contains(node.id.as_str()) - { - continue; - } - let domain = required_domain(&domains, &node.domain_id)?; - out.push(document( - swarm_id, - snapshot, - SemanticDocumentKind::Node, - &node.id, - domain, - node.profile, - SemanticLifecycle::Memory(node.lifecycle), - node.anchors - .iter() - .map(|anchor| anchor.target.clone()) - .collect(), - node.source_hashes.clone(), - node, - join_text([ - &node.title, - &node.claim, - &node.question, - &node.tension, - &node.action_implication, - ]), - )?); - } - - for edge in &snapshot.edges { - if !is_modeling_profile(edge.profile) - || excluded_lifecycle(edge.lifecycle) - || stale_edges.contains(edge.id.as_str()) - { - continue; - } - let source = nodes - .get(edge.source_id.as_str()) - .ok_or_else(|| anyhow!("validated edge lost source"))?; - let target = nodes - .get(edge.target_id.as_str()) - .ok_or_else(|| anyhow!("validated edge lost target"))?; - if excluded_lifecycle(source.lifecycle) - || excluded_lifecycle(target.lifecycle) - || !is_modeling_profile(source.profile) - || !is_modeling_profile(target.profile) - || stale_nodes.contains(source.id.as_str()) - || stale_nodes.contains(target.id.as_str()) - { - continue; - } - let domain = required_domain(&domains, &source.domain_id)?; - let source_hashes = edge - .anchors - .iter() - .filter_map(|anchor| anchor.source_hash.clone()) - .collect(); - out.push(document( - swarm_id, - snapshot, - SemanticDocumentKind::Edge, - &edge.id, - domain, - edge.profile, - SemanticLifecycle::Memory(edge.lifecycle), - edge.anchors - .iter() - .map(|anchor| anchor.target.clone()) - .collect(), - source_hashes, - edge, - join_text([&edge.claim, &edge.source_id, &edge.target_id]), - )?); - } - - for summary in &snapshot.summaries { - let domain = required_domain(&domains, &summary.domain_id)?; - if !is_modeling_profile(domain.profile) - || summary.freshness != EpiphanyMemoryFreshnessStatus::Ready - || summary.confidence < 70 - || !summary.known_omissions.is_empty() - || stale_summaries.contains(summary.id.as_str()) - { - continue; - } - out.push(document( - swarm_id, - snapshot, - SemanticDocumentKind::Summary, - &summary.id, - domain, - domain.profile, - SemanticLifecycle::Derived, - summary - .covers_node_ids - .iter() - .chain(&summary.covers_edge_ids) - .cloned() - .collect(), - summary.source_hashes.clone(), - summary, - join_text([ - &summary.target, - &summary.claim, - &summary.question, - &summary.tension, - &summary.action_implication, - ]), - )?); - } - - for item in &snapshot.frontier { - if !matches!( - item.status, - RepoFrontierStatus::Proposed | RepoFrontierStatus::Active | RepoFrontierStatus::Blocked - ) { - continue; - } - let domain = item - .target_claim_ids - .first() - .and_then(|id| nodes.get(id.as_str())) - .and_then(|node| domains.get(node.domain_id.as_str())) - .copied() - .ok_or_else(|| anyhow!("validated unresolved frontier lost its target domain"))?; - out.push(document( - swarm_id, - snapshot, - SemanticDocumentKind::Frontier, - &item.id, - domain, - EpiphanyMemoryProfile::RepoArchitecture, - SemanticLifecycle::Frontier(item.status), - item.repository_scope - .iter() - .chain(&item.evidence_refs) - .cloned() - .collect(), - Vec::new(), - item, - join_text([ - &item.migration_body, - &item.question, - &item.gap, - &item.recommended_next_organ, - ]), - )?); - } - - out.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - Ok(out) -} - -pub fn resolve_semantic_candidate<'a>( - candidate: &SemanticProjectionCandidate, - current_documents: &'a [SemanticProjectionDocument], -) -> Result<&'a SemanticProjectionDocument> { - let document = current_documents - .iter() - .find(|document| document.point_id == candidate.point_id) - .ok_or_else(|| anyhow!("semantic candidate is missing or no longer live"))?; - if document.canonical != candidate.canonical - || document.model_revision != candidate.indexed_model_revision - || document.model_hash != candidate.indexed_model_hash - || document.canonical_content_hash != candidate.indexed_canonical_content_hash - { - return Err(anyhow!( - "semantic candidate no longer matches canonical state" - )); - } - Ok(document) -} - -fn document( - swarm_id: &str, - snapshot: &EpiphanyMemoryGraphSnapshot, - kind: SemanticDocumentKind, - document_id: &str, - domain: &EpiphanyMemoryDomain, - profile: EpiphanyMemoryProfile, - lifecycle: SemanticLifecycle, - mut source_refs: Vec, - mut source_hashes: Vec, - canonical_value: &T, - projection_text: String, -) -> Result { - source_refs.sort(); - source_refs.dedup(); - source_hashes.sort(); - source_hashes.dedup(); - let canonical_type = match kind { - SemanticDocumentKind::Node => "epiphany.mind.repo_model.node.v1", - SemanticDocumentKind::Edge => "epiphany.mind.repo_model.edge.v1", - SemanticDocumentKind::Summary => "epiphany.mind.repo_model.summary.v1", - SemanticDocumentKind::Frontier => "epiphany.mind.repo_model.frontier.v1", - }; - let canonical = SemanticCanonicalLocator { - locator: format!("cultcache://{swarm_id}/{canonical_type}/{document_id}"), - canonical_type: canonical_type.to_string(), - canonical_key: document_id.to_string(), - canonical_document_id: document_id.to_string(), - }; - Ok(SemanticProjectionDocument { - point_id: semantic_point_id(swarm_id, canonical_type, document_id, document_id), - swarm_id: swarm_id.to_string(), - kind, - canonical, - graph_id: snapshot.graph_id.clone(), - model_revision: snapshot.model_revision, - model_hash: snapshot.model_hash.clone(), - domain_id: domain.id.clone(), - profile, - lifecycle, - visibility: SemanticVisibility::PrivateVerse, - source_refs, - source_hashes, - canonical_content_hash: format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(canonical_value)?) - ), - canonical_schema_version: snapshot - .schema_version - .clone() - .unwrap_or_else(|| "unknown".to_string()), - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - projection_text, - }) -} - -fn is_modeling_profile(profile: EpiphanyMemoryProfile) -> bool { - matches!( - profile, - EpiphanyMemoryProfile::RepoArchitecture | EpiphanyMemoryProfile::RepoDataflow - ) -} - -fn excluded_lifecycle(lifecycle: EpiphanyMemoryLifecycle) -> bool { - matches!( - lifecycle, - EpiphanyMemoryLifecycle::Retired | EpiphanyMemoryLifecycle::Stale - ) -} - -fn required_domain<'a>( - domains: &HashMap<&str, &'a EpiphanyMemoryDomain>, - id: &str, -) -> Result<&'a EpiphanyMemoryDomain> { - domains - .get(id) - .copied() - .ok_or_else(|| anyhow!("validated document lost domain")) -} - -fn join_text(parts: [&str; N]) -> String { - parts - .into_iter() - .filter(|part| !part.trim().is_empty()) - .collect::>() - .join("\n") -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::memory_graph::{ - EpiphanyMemoryEdge, EpiphanyMemoryNode, EpiphanyMemorySummary, RepoFrontierItem, - }; - use epiphany_state_model::{EpiphanyMemoryEdgeKind, EpiphanyMemoryNodeKind}; - - fn snapshot() -> EpiphanyMemoryGraphSnapshot { - let mut snapshot = EpiphanyMemoryGraphSnapshot { - schema_version: Some("v0".into()), - graph_id: "graph".into(), - model_revision: 7, - domains: vec![ - EpiphanyMemoryDomain { - id: "repo".into(), - profile: EpiphanyMemoryProfile::RepoArchitecture, - title: "Repo".into(), - lifecycle: EpiphanyMemoryLifecycle::Accepted, - ..Default::default() - }, - EpiphanyMemoryDomain { - id: "mind".into(), - profile: EpiphanyMemoryProfile::Evidence, - title: "Mind".into(), - lifecycle: EpiphanyMemoryLifecycle::Accepted, - ..Default::default() - }, - ], - nodes: vec![ - EpiphanyMemoryNode { - id: "repo-node".into(), - domain_id: "repo".into(), - profile: EpiphanyMemoryProfile::RepoArchitecture, - kind: EpiphanyMemoryNodeKind::Module, - title: "Repo node".into(), - claim: "owns map".into(), - tension: "map can drift".into(), - action_implication: "keep typed".into(), - source_hashes: vec!["anchor:missing".into()], - lifecycle: EpiphanyMemoryLifecycle::Accepted, - confidence: 90, - ..Default::default() - }, - EpiphanyMemoryNode { - id: "mind-node".into(), - domain_id: "mind".into(), - profile: EpiphanyMemoryProfile::Evidence, - kind: EpiphanyMemoryNodeKind::Evidence, - title: "Lesson".into(), - claim: "remember it".into(), - tension: "memory can drift".into(), - action_implication: "rehydrate".into(), - source_hashes: vec!["anchor:missing".into()], - lifecycle: EpiphanyMemoryLifecycle::Accepted, - confidence: 90, - ..Default::default() - }, - EpiphanyMemoryNode { - id: "retired".into(), - domain_id: "repo".into(), - profile: EpiphanyMemoryProfile::RepoArchitecture, - kind: EpiphanyMemoryNodeKind::Module, - title: "Old".into(), - claim: "old".into(), - tension: "obsolete".into(), - action_implication: "none".into(), - source_hashes: vec!["anchor:missing".into()], - lifecycle: EpiphanyMemoryLifecycle::Retired, - confidence: 90, - ..Default::default() - }, - ], - edges: vec![EpiphanyMemoryEdge { - id: "edge".into(), - source_id: "repo-node".into(), - target_id: "mind-node".into(), - kind: EpiphanyMemoryEdgeKind::Grounds, - profile: EpiphanyMemoryProfile::RepoArchitecture, - claim: "grounds".into(), - lifecycle: EpiphanyMemoryLifecycle::Accepted, - confidence: 80, - ..Default::default() - }], - summaries: vec![EpiphanyMemorySummary { - id: "summary".into(), - domain_id: "mind".into(), - covers_node_ids: vec!["mind-node".into()], - target: "lesson".into(), - claim: "durable".into(), - tension: "retrieval can drift".into(), - action_implication: "retrieve".into(), - freshness: EpiphanyMemoryFreshnessStatus::Ready, - confidence: 80, - ..Default::default() - }], - frontier: vec![RepoFrontierItem { - id: "frontier".into(), - migration_body: "finish projection".into(), - gap: "not wired".into(), - target_claim_ids: vec!["repo-node".into()], - repository_scope: vec!["epiphany-core".into()], - recommended_next_organ: "Hands".into(), - status: RepoFrontierStatus::Active, - ..Default::default() - }], - ..Default::default() - }; - snapshot.model_hash = memory_graph_model_hash(&snapshot).unwrap(); - snapshot - } - - #[test] - fn derives_only_live_modeling_documents() { - let documents = derive_semantic_projection("swarm-a", &snapshot()).unwrap(); - assert_eq!(documents.len(), 2); - assert!( - documents - .iter() - .any(|document| document.kind == SemanticDocumentKind::Frontier) - ); - assert!( - !documents - .iter() - .any(|document| document.canonical.canonical_document_id == "retired") - ); - let first = derive_semantic_projection("swarm-a", &snapshot()).unwrap(); - assert_eq!(documents, first); - let other_swarm = derive_semantic_projection("swarm-b", &snapshot()).unwrap(); - assert!(documents.iter().zip(&other_swarm).all(|(left, right)| { - left.swarm_id != right.swarm_id && left.point_id != right.point_id - })); - } - - #[test] - fn candidate_resolution_revalidates_canonical_identity_and_hashes() { - let documents = derive_semantic_projection("swarm-a", &snapshot()).unwrap(); - let document = documents - .iter() - .find(|document| document.canonical.canonical_document_id == "repo-node") - .unwrap(); - let candidate = SemanticProjectionCandidate { - point_id: document.point_id.clone(), - canonical: document.canonical.clone(), - score: 0.9, - indexed_model_revision: document.model_revision, - indexed_model_hash: document.model_hash.clone(), - indexed_canonical_content_hash: document.canonical_content_hash.clone(), - }; - assert_eq!( - resolve_semantic_candidate(&candidate, &documents) - .unwrap() - .point_id, - document.point_id - ); - let mut stale = candidate.clone(); - stale.indexed_canonical_content_hash = "stale".into(); - assert!(resolve_semantic_candidate(&stale, &documents).is_err()); - let mut stale_revision = candidate.clone(); - stale_revision.indexed_model_revision -= 1; - assert!(resolve_semantic_candidate(&stale_revision, &documents).is_err()); - let mut stale_model = candidate.clone(); - stale_model.indexed_model_hash = "old-model".into(); - assert!(resolve_semantic_candidate(&stale_model, &documents).is_err()); - let mut wrong_locator = candidate.clone(); - wrong_locator.canonical.canonical_document_id = "other".into(); - assert!(resolve_semantic_candidate(&wrong_locator, &documents).is_err()); - assert!(resolve_semantic_candidate(&candidate, &[]).is_err()); - } - - #[test] - fn ranked_edge_cannot_reintroduce_stale_endpoint_and_summary_is_not_duplicated() { - let mut snapshot = snapshot(); - snapshot.nodes[0].lifecycle = EpiphanyMemoryLifecycle::Stale; - snapshot.summaries[0].freshness = EpiphanyMemoryFreshnessStatus::Ready; - snapshot.freshness = Some(crate::memory_graph::derive_memory_graph_freshness( - &snapshot, - &[], - )); - snapshot.model_hash.clear(); - snapshot.model_hash = memory_graph_model_hash(&snapshot).unwrap(); - let packet = crate::memory_graph::plan_memory_graph_context_cut_with_ranked_ids( - &snapshot, - &crate::memory_graph::EpiphanyMemoryContextQuery { - id: "ranked-hostile".to_string(), - text: Some("durable lesson".to_string()), - ..Default::default() - }, - &["edge".to_string(), "summary".to_string()], - ); - assert!(!packet.nodes.iter().any(|node| node.id == "repo-node")); - assert_eq!( - packet - .summaries - .iter() - .filter(|summary| summary.id == "summary") - .count(), - 1 - ); - } - - #[test] - fn stale_summary_descent_never_emits_stale_children() { - let mut snapshot = snapshot(); - snapshot.nodes[0].lifecycle = EpiphanyMemoryLifecycle::Stale; - snapshot.summaries[0].covers_node_ids = vec!["repo-node".to_string()]; - snapshot.summaries[0].freshness = EpiphanyMemoryFreshnessStatus::Stale; - snapshot.freshness = Some(crate::memory_graph::derive_memory_graph_freshness( - &snapshot, - &[], - )); - let packet = crate::memory_graph::plan_memory_graph_context_cut( - &snapshot, - &crate::memory_graph::EpiphanyMemoryContextQuery { - id: "stale-summary".to_string(), - text: Some("durable".to_string()), - ..Default::default() - }, - ); - assert!(!packet.nodes.iter().any(|node| node.id == "repo-node")); - assert!(packet.summaries.is_empty()); - } - - #[test] - fn modeling_cut_cannot_cross_domain_through_ranked_ids() { - let mut snapshot = snapshot(); - snapshot.frontier.push(RepoFrontierItem { - id: "mind-frontier".into(), - migration_body: "tempt cross-partition routing".into(), - gap: "must remain private to Mind".into(), - target_claim_ids: vec!["mind-node".into()], - recommended_next_organ: "Self".into(), - status: RepoFrontierStatus::Active, - ..Default::default() - }); - let modeling = crate::memory_graph::plan_modeling_context_cut( - &snapshot, - &crate::memory_graph::EpiphanyMemoryContextQuery { - id: "hostile-modeling".into(), - domain_ids: vec!["repo".into()], - node_ids: vec!["mind-node".into()], - edge_ids: vec!["edge".into()], - text: Some("remember durable lesson".into()), - budget: Some(64), - ..Default::default() - }, - &["mind-node".into(), "edge".into(), "summary".into()], - ); - assert!(modeling.nodes.iter().all(|node| { - node.domain_id == "repo" - && matches!( - node.profile, - EpiphanyMemoryProfile::RepoArchitecture | EpiphanyMemoryProfile::RepoDataflow - ) - })); - assert!(modeling.edges.is_empty()); - assert!(modeling.summaries.is_empty()); - assert_eq!( - modeling - .frontier - .iter() - .map(|item| item.id.as_str()) - .collect::>(), - vec!["frontier"] - ); - } -} diff --git a/epiphany-core/src/memory_graph/semantic_projector.rs b/epiphany-core/src/memory_graph/semantic_projector.rs deleted file mode 100644 index 3a7cc52f..00000000 --- a/epiphany-core/src/memory_graph/semantic_projector.rs +++ /dev/null @@ -1,4131 +0,0 @@ -use super::{ - MEMORY_SEMANTIC_PROJECTION_ATTEMPT_SCHEMA_VERSION, MemorySemanticIndexReceipt, - MemorySemanticProjectionAttempt, MemorySemanticProjectionObligation, - MemorySemanticProjectionSourceHead, bind_memory_semantic_index_receipt, - memory_semantic_projection_terminal_success, validate_memory_semantic_projection_attempt, - validate_memory_semantic_projection_obligation, -}; -use anyhow::{Result, anyhow}; -use cultcache_rs::{ - CacheBackingStore, CultCache, CultCacheEnvelope, DatabaseEntry, - SingleFileMessagePackBackingStore, -}; -use serde::de::DeserializeOwned; -use sha2::{Digest, Sha256}; -use std::collections::{BTreeMap, BTreeSet}; -use std::path::Path; - -trait MemorySemanticPhysicalRetirementPort { - fn point_ids_for_scope( - &mut self, - collection: &str, - scope: &[(&str, &str)], - ) -> Result>; - fn delete_points(&mut self, collection: &str, point_ids: &[String]) -> Result<()>; -} - -impl MemorySemanticPhysicalRetirementPort for crate::semantic_backend::QdrantBackend { - fn point_ids_for_scope( - &mut self, - collection: &str, - scope: &[(&str, &str)], - ) -> Result> { - crate::semantic_backend::QdrantBackend::point_ids_for_scope(self, collection, scope) - } - - fn delete_points(&mut self, collection: &str, point_ids: &[String]) -> Result<()> { - crate::semantic_backend::QdrantBackend::delete_points(self, collection, point_ids) - } -} - -pub const MEMORY_SEMANTIC_PROJECTION_CLAIM_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_projection_claim.v1"; -pub const MEMORY_SEMANTIC_PROJECTOR_EXECUTOR_GRANT_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_projector_executor_grant.v1"; -pub const MEMORY_SEMANTIC_PROJECTOR_RECOVERY_AUTHORIZATION_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_projector_recovery_authorization.v2"; -pub const MEMORY_SEMANTIC_PROJECTION_RETENTION_HEAD_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_projection_retention_head.v0"; -pub const MEMORY_SEMANTIC_PHYSICAL_RETIREMENT_OBLIGATION_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_physical_retirement_obligation.v0"; -pub const MEMORY_SEMANTIC_PHYSICAL_RETIREMENT_RECEIPT_SCHEMA_VERSION: &str = - "gamecult.epiphany.memory_semantic_physical_retirement_receipt.v0"; - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_projection_retention_head", - schema = "MemorySemanticProjectionRetentionHead" -)] -pub struct MemorySemanticProjectionRetentionHead { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub scope_id: String, - #[cultcache(key = 2)] - pub revision: u64, - #[cultcache(key = 3)] - pub retired_generation_count: u64, - #[cultcache(key = 4)] - pub retired_envelope_count: u64, - #[cultcache(key = 5)] - pub retired_type_counts: BTreeMap, - #[cultcache(key = 6)] - pub retired_status_counts: BTreeMap, - #[cultcache(key = 7)] - pub retired_chain_digest: String, - #[cultcache(key = 8)] - pub retained_at: String, - #[cultcache(key = 9)] - pub private_state_exposed: bool, -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_physical_retirement_obligation", - schema = "MemorySemanticPhysicalRetirementObligation" -)] -pub struct MemorySemanticPhysicalRetirementObligation { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub retirement_id: String, - #[cultcache(key = 2)] - pub scope_id: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub partition: String, - #[cultcache(key = 5)] - pub obligation_id: String, - #[cultcache(key = 6)] - pub attempt_id: String, - #[cultcache(key = 7)] - pub claim_id: String, - #[cultcache(key = 8)] - pub claim_epoch: u64, - #[cultcache(key = 9)] - pub physical_backend_url: String, - #[cultcache(key = 10)] - pub collection_name: String, - #[cultcache(key = 11)] - pub retention_authorization_sha256: String, - #[cultcache(key = 12)] - pub authorized_at: String, - #[cultcache(key = 13)] - pub private_state_exposed: bool, -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_physical_retirement_receipt", - schema = "MemorySemanticPhysicalRetirementReceipt" -)] -pub struct MemorySemanticPhysicalRetirementReceipt { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub receipt_id: String, - #[cultcache(key = 2)] - pub retirement_id: String, - #[cultcache(key = 3)] - pub observed_point_count: u64, - #[cultcache(key = 4)] - pub deleted_point_count: u64, - #[cultcache(key = 5)] - pub completed_at: String, - #[cultcache(key = 6)] - pub private_state_exposed: bool, -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_projector_executor_grant", - schema = "MemorySemanticProjectorExecutorGrant" -)] -pub struct MemorySemanticProjectorExecutorGrant { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub grant_id: String, - #[cultcache(key = 2)] - pub scope_id: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub partition: String, - #[cultcache(key = 5)] - pub obligation_id: String, - #[cultcache(key = 6)] - pub executor_id: String, - #[cultcache(key = 7)] - pub executor_incarnation: String, - #[cultcache(key = 8)] - pub purpose: String, - #[cultcache(key = 9)] - pub issuer_id: String, - #[cultcache(key = 10)] - pub issuer_incarnation: String, - #[cultcache(key = 11)] - pub status: String, - #[cultcache(key = 12)] - pub issued_at: String, - #[cultcache(key = 13)] - pub consumed_at: Option, - #[cultcache(key = 14)] - pub resulting_claim_id: Option, - #[cultcache(key = 15)] - pub resulting_claim_epoch: Option, - #[cultcache(key = 16)] - pub predecessor_claim_id: Option, - #[cultcache(key = 17)] - pub predecessor_claim_epoch: Option, - #[cultcache(key = 18)] - pub predecessor_claim_status: String, -} - -#[cfg(test)] -mod authority_tests { - use super::*; - use crate::{ - MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION, SEMANTIC_PROJECTION_SCHEMA_VERSION, - }; - use anyhow::Context; - use tempfile::tempdir; - - fn obligation() -> MemorySemanticProjectionObligation { - MemorySemanticProjectionObligation { - schema_version: MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION.to_string(), - obligation_id: "obligation-modeling-7".into(), - swarm_id: "swarm-a".into(), - partition: "modeling".into(), - canonical_source_id: "runtime/repo-model".into(), - source_commit_id: "admission-7".into(), - graph_id: "repo-model".into(), - source_generation: 7, - source_model_hash: "model-hash-7".into(), - canonical_content_set_hash: "content-set-7".into(), - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.into(), - created_at: "2026-07-15T04:00:00Z".into(), - } - } - - fn input( - store: &Path, - obligation: &MemorySemanticProjectionObligation, - ) -> Result { - let envelopes = SingleFileMessagePackBackingStore::new(store).pull_all()?; - let authority = exact_envelope( - &envelopes, - MemorySemanticProjectionObligation::TYPE, - &obligation.obligation_id, - )?; - Ok(MemorySemanticProjectionInput { - snapshot: super::super::EpiphanyMemoryGraphSnapshot { - schema_version: Some("v0".to_string()), - graph_id: obligation.graph_id.clone(), - model_revision: obligation.source_generation, - ..Default::default() - }, - obligation: obligation.clone(), - authority: MemorySemanticProjectionAuthoritySnapshot { - head: MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }, - envelopes: vec![authority], - }, - }) - } - - #[test] - fn acquisition_persists_exact_physical_namespace() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("physical-namespace.cc"); - let obligation = obligation(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let input = input(&store, &obligation)?; - let mut config = super::super::MemorySemanticIndexConfig::from_env(); - config.qdrant_url = "http://qdrant-history:6333".into(); - config.modeling_collection = "modeling-history-v9".into(); - let acquisition = idunn_acquire_memory_semantic_projection_with_config( - &store, - &input, - "executor-a", - "executor-incarnation-a", - "execute", - "idunn-a", - "2026-07-15T04:01:00Z", - &config, - )?; - let rows = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let attempt = - decode_one::(&rows, &acquisition.claim.attempt_id)? - .context("acquired attempt missing")?; - assert_eq!(attempt.physical_backend_url, config.qdrant_url); - assert_eq!(attempt.collection_name, config.modeling_collection); - Ok(()) - } - - #[test] - fn execution_refuses_a_substituted_physical_namespace_before_backend_io() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("substituted-namespace.cc"); - let obligation = obligation(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let input = input(&store, &obligation)?; - let mut acquired = super::super::MemorySemanticIndexConfig::from_env(); - acquired.qdrant_url = "http://qdrant-history:6333".into(); - acquired.modeling_collection = "modeling-history-v9".into(); - let acquisition = idunn_acquire_memory_semantic_projection_with_config( - &store, - &input, - "executor-a", - "executor-incarnation-a", - "execute", - "idunn-a", - "2026-07-15T04:01:00Z", - &acquired, - )?; - let mut substituted = acquired.clone(); - substituted.qdrant_url = "http://foreign-qdrant:6333".into(); - let error = execute_memory_semantic_projection( - &store, - &input, - &acquisition.claim.claim_id, - &substituted, - ) - .expect_err("substituted physical namespace must fail closed"); - assert!(error.to_string().contains("acquired physical namespace")); - let rows = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let attempt = - decode_one::(&rows, &acquisition.claim.attempt_id)? - .context("failed attempt missing")?; - assert_eq!(attempt.status, "failed"); - assert_eq!(attempt.physical_backend_url, acquired.qdrant_url); - assert_eq!(attempt.collection_name, acquired.modeling_collection); - Ok(()) - } - - #[test] - fn empty_projection_terminal_succeeds_once_without_becoming_query_eligible() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("empty-terminal.cc"); - let mut obligation = obligation(); - obligation.canonical_content_set_hash = format!("{:x}", Sha256::digest([])); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let input = input(&store, &obligation)?; - let acquisition = idunn_acquire_memory_semantic_projection( - &store, - &input, - "executor-a", - "executor-incarnation-a", - "execute", - "idunn-a", - "2026-07-15T04:01:00Z", - )?; - let receipt = MemorySemanticIndexReceipt { - schema_version: crate::MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id: "empty-receipt".into(), - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - collection_name: "epiphany_modeling_v1".into(), - graph_id: obligation.graph_id.clone(), - model_revision: obligation.source_generation, - model_hash: obligation.source_model_hash.clone(), - embedding_provider_id: "provider".into(), - embedding_model: "model".into(), - vector_dimensions: 0, - indexed_document_count: 0, - deleted_document_count: 0, - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - indexed_at: "2026-07-15T04:02:00Z".into(), - status: "ready".into(), - obligation_id: obligation.obligation_id.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - source_generation: obligation.source_generation, - projection_schema_version: obligation.projection_schema_version.clone(), - claim_id: acquisition.claim.claim_id.clone(), - claim_epoch: acquisition.claim.epoch, - observed_vector_binding_root_sha256: format!("{:x}", Sha256::digest([])), - }; - succeed_memory_semantic_projection_claim( - &store, - &acquisition.claim.claim_id, - &input.authority, - receipt, - "2026-07-15T04:02:01Z", - )?; - let readiness = load_memory_semantic_projection_readiness(&store, &input)? - .expect("terminal empty receipt remains authenticated"); - assert!(!super::super::memory_semantic_projection_query_eligible( - &obligation, - &input.authority.head, - &readiness.receipt - )); - assert_eq!( - classify_memory_semantic_projection_for_pulse(&store, &input)?, - crate::MemorySemanticProjectorPulseClassification::Ready - ); - assert!( - idunn_acquire_memory_semantic_projection( - &store, - &input, - "executor-b", - "executor-incarnation-b", - "execute", - "idunn-b", - "2026-07-15T04:03:00Z", - ) - .is_err() - ); - let mut legacy = readiness.receipt; - legacy.schema_version = "gamecult.epiphany.memory_semantic_index_receipt.v1".into(); - legacy.observed_vector_binding_root_sha256.clear(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&legacy.receipt_id, &legacy)?; - assert_eq!( - classify_memory_semantic_projection_for_pulse(&store, &input)?, - crate::MemorySemanticProjectorPulseClassification::Repair - ); - let scope_id = projection_scope_id(&obligation.swarm_id, &obligation.partition)?; - cache.pull_all_backing_stores()?; - let current = cache - .get::(&scope_id)? - .expect("succeeded predecessor"); - let mut forged = current.clone(); - forged.authority_id = "missing-consumed-authority".into(); - cache.put(&scope_id, &forged)?; - assert!(classify_memory_semantic_projection_for_pulse(&store, &input).is_err()); - assert!( - idunn_acquire_memory_semantic_projection( - &store, - &input, - "executor-b", - "executor-incarnation-b", - "repair", - "idunn-b", - "2026-07-15T04:03:00Z", - ) - .is_err() - ); - cache.put(&scope_id, ¤t)?; - let repair = idunn_acquire_memory_semantic_projection( - &store, - &input, - "executor-b", - "executor-incarnation-b", - "repair", - "idunn-b", - "2026-07-15T04:03:00Z", - )?; - assert_eq!(repair.claim.epoch, acquisition.claim.epoch + 1); - fail_memory_semantic_projection_claim( - &store, - &repair.claim.claim_id, - "2026-07-15T04:04:00Z", - "transient embedding failure", - )?; - assert_eq!( - classify_memory_semantic_projection_for_pulse(&store, &input)?, - crate::MemorySemanticProjectorPulseClassification::Failed - ); - let retry = idunn_acquire_memory_semantic_projection( - &store, - &input, - "executor-c", - "executor-incarnation-c", - "execute", - "idunn-c", - "2026-07-15T04:05:00Z", - )?; - assert_eq!(retry.claim.epoch, repair.claim.epoch + 1); - let migrated = MemorySemanticIndexReceipt { - schema_version: crate::MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id: "empty-receipt-v2".into(), - indexed_at: "2026-07-15T04:06:00Z".into(), - claim_id: retry.claim.claim_id.clone(), - claim_epoch: retry.claim.epoch, - observed_vector_binding_root_sha256: format!("{:x}", Sha256::digest([])), - ..legacy - }; - succeed_memory_semantic_projection_claim( - &store, - &retry.claim.claim_id, - &input.authority, - migrated, - "2026-07-15T04:06:01Z", - )?; - assert_eq!( - classify_memory_semantic_projection_for_pulse(&store, &input)?, - crate::MemorySemanticProjectorPulseClassification::Ready - ); - Ok(()) - } - - #[test] - fn concurrent_idunn_acquisition_has_one_winner_and_no_issued_litter() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("acquisition.msgpack"); - let obligation = obligation(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let projection_input = input(&store, &obligation)?; - let barrier = std::sync::Arc::new(std::sync::Barrier::new(3)); - let mut workers = Vec::new(); - for executor in ["executor-a", "executor-b"] { - let store = store.clone(); - let projection_input = projection_input.clone(); - let barrier = barrier.clone(); - workers.push(std::thread::spawn(move || { - barrier.wait(); - idunn_acquire_memory_semantic_projection( - store, - &projection_input, - executor, - &format!("{executor}-incarnation"), - "execute", - "idunn-incarnation-a", - "2026-07-15T04:01:00Z", - ) - })); - } - barrier.wait(); - let results = workers - .into_iter() - .map(|worker| worker.join().expect("worker")) - .collect::>(); - assert_eq!(results.iter().filter(|result| result.is_ok()).count(), 1); - let envelopes = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let grants = decode_all::(&envelopes)?; - assert_eq!(grants.len(), 1); - assert!(grants.iter().all(|grant| grant.status == "consumed")); - let claim = decode_all::(&envelopes)? - .pop() - .expect("claim"); - authenticate_claim_authority_from_envelopes(&envelopes, &claim)?; - Ok(()) - } - - #[test] - fn acquisition_is_epoch_bound_and_timestamp_ordered() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("ordering.msgpack"); - let obligation = obligation(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let projection_input = input(&store, &obligation)?; - assert!( - idunn_acquire_memory_semantic_projection( - &store, - &projection_input, - "executor-a", - "executor-a-incarnation", - "execute", - "idunn-incarnation-a", - "2026-07-15T03:59:59Z" - ) - .is_err() - ); - let acquisition = idunn_acquire_memory_semantic_projection( - &store, - &projection_input, - "executor-a", - "executor-a-incarnation", - "execute", - "idunn-incarnation-a", - "2026-07-15T04:01:00Z", - )?; - assert_eq!(acquisition.grant.predecessor_claim_status, "absent"); - assert_eq!(acquisition.grant.resulting_claim_epoch, Some(1)); - assert_eq!(acquisition.claim.authority_id, acquisition.grant.grant_id); - fail_memory_semantic_projection_claim( - &store, - &acquisition.claim.claim_id, - "2026-07-15T04:02:00Z", - "test failure", - )?; - let successor = idunn_acquire_memory_semantic_projection( - &store, - &projection_input, - "executor-b", - "executor-b-incarnation", - "execute", - "idunn-incarnation-a", - "2026-07-15T04:03:00Z", - )?; - assert_eq!( - successor.grant.predecessor_claim_id.as_deref(), - Some(acquisition.claim.claim_id.as_str()) - ); - assert_eq!(successor.grant.predecessor_claim_epoch, Some(1)); - assert_eq!(successor.grant.predecessor_claim_status, "failed"); - assert_eq!(successor.claim.epoch, 2); - Ok(()) - } - - #[test] - fn acquisition_refuses_advanced_non_obligation_authority() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("stale-acquisition.msgpack"); - let obligation = obligation(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let marker_key = "canonical-head-marker"; - cache.put(marker_key, &obligation)?; - let mut projection_input = input(&store, &obligation)?; - let opening = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - projection_input.authority.envelopes.push(exact_envelope( - &opening, - MemorySemanticProjectionObligation::TYPE, - marker_key, - )?); - let mut advanced = obligation.clone(); - advanced.source_generation += 1; - advanced.source_model_hash = "advanced-model-hash".to_string(); - advanced.canonical_content_set_hash = "advanced-content-hash".to_string(); - cache.put(marker_key, &advanced)?; - assert!( - idunn_acquire_memory_semantic_projection( - &store, - &projection_input, - "executor-stale", - "executor-stale-incarnation", - "execute", - "idunn-incarnation-a", - "2026-07-15T04:01:00Z", - ) - .is_err() - ); - Ok(()) - } - - #[test] - fn sealed_recovery_binds_lifecycle_receipt_and_provider_heartbeat() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("recovery.msgpack"); - let obligation = obligation(); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&obligation.obligation_id, &obligation)?; - let projection_input = input(&store, &obligation)?; - let acquisition = idunn_acquire_memory_semantic_projection( - &store, - &projection_input, - "executor-a", - "provider-old", - "execute", - "idunn-incarnation-a", - "2026-07-15T04:01:00Z", - )?; - let evidence = idunn_semantic_recovery_evidence_from_cultmesh( - &store, - &projection_input, - &acquisition.claim.claim_id, - "idunn-incarnation-a", - "managed-policy-1", - "sha256-policy", - "launch-receipt-1", - "sha256-launch-receipt", - "2026-07-15T04:02:00Z", - "heartbeat-1", - "sha256-heartbeat", - "provider-new", - "2026-07-15T04:03:00Z", - "launch-receipt-1", - )?; - let (authorization, recovered) = idunn_recover_memory_semantic_projection( - &store, - &projection_input, - &acquisition.claim.claim_id, - "executor-b", - "provider-new", - &evidence, - "2026-07-15T04:04:00Z", - )?; - assert_eq!(authorization.status, "consumed"); - assert_eq!(authorization.managed_service_policy_id, "managed-policy-1"); - assert_eq!( - authorization.launch_lifecycle_receipt_id, - "launch-receipt-1" - ); - assert_eq!(authorization.provider_heartbeat_id, "heartbeat-1"); - assert_eq!( - authorization.provider_incarnation, - recovered.executor_incarnation - ); - assert_eq!(recovered.authority_id, authorization.authorization_id); - assert!( - fail_memory_semantic_projection_claim( - &store, - &acquisition.claim.claim_id, - "2026-07-15T04:05:00Z", - "late old executor" - ) - .is_err() - ); - assert!( - idunn_semantic_recovery_evidence_from_cultmesh( - &store, - &projection_input, - &recovered.claim_id, - "idunn-incarnation-a", - "managed-policy-2", - "sha256-policy-2", - "launch-receipt-2", - "sha256-launch-receipt-2", - "2026-07-15T04:03:00Z", - "heartbeat-2", - "sha256-heartbeat-2", - "provider-new", - "2026-07-15T04:03:00Z", - "launch-receipt-2", - ) - .is_err() - ); - Ok(()) - } -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_projector_recovery_authorization", - schema = "MemorySemanticProjectorRecoveryAuthorization" -)] -pub struct MemorySemanticProjectorRecoveryAuthorization { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub authorization_id: String, - #[cultcache(key = 2)] - pub scope_id: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub partition: String, - #[cultcache(key = 5)] - pub obligation_id: String, - #[cultcache(key = 6)] - pub claim_id: String, - #[cultcache(key = 7)] - pub claim_epoch: u64, - #[cultcache(key = 8)] - pub attempt_id: String, - #[cultcache(key = 9)] - pub abandoned_executor_id: String, - #[cultcache(key = 10)] - pub replacement_executor_id: String, - #[cultcache(key = 11)] - pub replacement_executor_incarnation: String, - #[cultcache(key = 12)] - pub issuer_id: String, - #[cultcache(key = 13)] - pub issuer_incarnation: String, - #[cultcache(key = 14)] - pub managed_service_policy_id: String, - #[cultcache(key = 15)] - pub managed_service_policy_digest: String, - #[cultcache(key = 16)] - pub status: String, - #[cultcache(key = 17)] - pub issued_at: String, - #[cultcache(key = 18)] - pub consumed_at: Option, - #[cultcache(key = 19)] - pub resulting_claim_id: Option, - #[cultcache(key = 20)] - pub resulting_claim_epoch: Option, - #[cultcache(key = 21)] - pub abandoned_executor_incarnation: String, - #[cultcache(key = 22)] - pub launch_lifecycle_receipt_id: String, - #[cultcache(key = 23)] - pub launch_lifecycle_receipt_digest: String, - #[cultcache(key = 24)] - pub launch_lifecycle_receipt_completed_at: String, - #[cultcache(key = 25)] - pub provider_heartbeat_id: String, - #[cultcache(key = 26)] - pub provider_heartbeat_digest: String, - #[cultcache(key = 27)] - pub provider_incarnation: String, - #[cultcache(key = 28)] - pub provider_heartbeat_at: String, - #[cultcache(key = 29)] - pub canonical_store_id: String, - #[cultcache(key = 30)] - pub startup_correlation_id: String, -} - -#[derive(Clone, Debug, PartialEq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.memory_semantic_projection_claim", - schema = "MemorySemanticProjectionClaim" -)] -pub struct MemorySemanticProjectionClaim { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub scope_id: String, - #[cultcache(key = 2)] - pub claim_id: String, - #[cultcache(key = 3)] - pub obligation_id: String, - #[cultcache(key = 4)] - pub attempt_id: String, - #[cultcache(key = 5)] - pub executor_id: String, - #[cultcache(key = 6)] - pub epoch: u64, - #[cultcache(key = 7)] - pub status: String, - #[cultcache(key = 8)] - pub claimed_at: String, - #[cultcache(key = 9)] - pub completed_at: Option, - #[cultcache(key = 10)] - pub executor_incarnation: String, - #[cultcache(key = 11)] - pub authority_kind: String, - #[cultcache(key = 12)] - pub authority_id: String, -} - -#[allow(dead_code)] // Sealed until Idunn can supply authenticated lifecycle evidence. -#[derive(Clone, Debug)] -pub struct IdunnSemanticRecoveryEvidence { - issuer_incarnation: String, - managed_service_policy_id: String, - managed_service_policy_digest: String, - launch_lifecycle_receipt_id: String, - launch_lifecycle_receipt_digest: String, - launch_lifecycle_receipt_completed_at: String, - provider_heartbeat_id: String, - provider_heartbeat_digest: String, - provider_incarnation: String, - provider_heartbeat_at: String, - canonical_store_id: String, - scope_id: String, - swarm_id: String, - partition: String, - obligation_id: String, - claim_id: String, - claim_epoch: u64, - abandoned_executor_incarnation: String, - startup_correlation_id: String, -} - -#[allow(clippy::too_many_arguments)] -pub(crate) fn idunn_semantic_recovery_evidence_from_cultmesh( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - expected_claim_id: &str, - issuer_incarnation: &str, - managed_service_policy_id: &str, - managed_service_policy_digest: &str, - launch_lifecycle_receipt_id: &str, - launch_lifecycle_receipt_digest: &str, - launch_lifecycle_receipt_completed_at: &str, - provider_heartbeat_id: &str, - provider_heartbeat_digest: &str, - provider_incarnation: &str, - provider_heartbeat_at: &str, - startup_correlation_id: &str, -) -> Result { - validate_memory_semantic_projection_obligation(&input.obligation)?; - let store_path = store_path.as_ref(); - let envelopes = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &envelopes, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - let persisted_obligation = decode_one::( - &envelopes, - &input.obligation.obligation_id, - )? - .ok_or_else(|| anyhow!("recovery evidence canonical obligation disappeared"))?; - if persisted_obligation != input.obligation { - return Err(anyhow!("recovery evidence canonical obligation advanced")); - } - for expected in &input.authority.envelopes { - let persisted = envelopes - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - .ok_or_else(|| anyhow!("recovery evidence input authority disappeared"))?; - if persisted != expected { - return Err(anyhow!("recovery evidence input authority advanced")); - } - } - let scope_id = projection_scope_id(&input.obligation.swarm_id, &input.obligation.partition)?; - let claim = decode_one::(&envelopes, &scope_id)? - .ok_or_else(|| anyhow!("recovery evidence requires current scope claim"))?; - validate_memory_semantic_projection_claim(&claim)?; - if claim.claim_id != expected_claim_id - || claim.obligation_id != input.obligation.obligation_id - || claim.status != "running" - { - return Err(anyhow!( - "recovery evidence claim does not match canonical input" - )); - } - authenticate_claim_authority_from_envelopes(&envelopes, &claim)?; - let evidence = IdunnSemanticRecoveryEvidence { - issuer_incarnation: issuer_incarnation.to_string(), - managed_service_policy_id: managed_service_policy_id.to_string(), - managed_service_policy_digest: managed_service_policy_digest.to_string(), - launch_lifecycle_receipt_id: launch_lifecycle_receipt_id.to_string(), - launch_lifecycle_receipt_digest: launch_lifecycle_receipt_digest.to_string(), - launch_lifecycle_receipt_completed_at: launch_lifecycle_receipt_completed_at.to_string(), - provider_heartbeat_id: provider_heartbeat_id.to_string(), - provider_heartbeat_digest: provider_heartbeat_digest.to_string(), - provider_incarnation: provider_incarnation.to_string(), - provider_heartbeat_at: provider_heartbeat_at.to_string(), - canonical_store_id: memory_semantic_projector_store_id(store_path)?, - scope_id, - swarm_id: input.obligation.swarm_id.clone(), - partition: input.obligation.partition.clone(), - obligation_id: input.obligation.obligation_id.clone(), - claim_id: claim.claim_id, - claim_epoch: claim.epoch, - abandoned_executor_incarnation: claim.executor_incarnation, - startup_correlation_id: startup_correlation_id.to_string(), - }; - validate_idunn_semantic_recovery_evidence(&evidence)?; - Ok(evidence) -} - -#[derive(Clone, Debug, PartialEq)] -pub struct MemorySemanticProjectorAcquisition { - pub grant: MemorySemanticProjectorExecutorGrant, - pub claim: MemorySemanticProjectionClaim, -} - -#[derive(Clone, Debug)] -pub(crate) struct MemorySemanticProjectionAuthoritySnapshot { - pub(crate) head: MemorySemanticProjectionSourceHead, - pub(crate) envelopes: Vec, -} - -#[derive(Clone, Debug)] -pub struct MemorySemanticProjectionInput { - pub(crate) snapshot: super::EpiphanyMemoryGraphSnapshot, - pub(crate) obligation: MemorySemanticProjectionObligation, - pub(crate) authority: MemorySemanticProjectionAuthoritySnapshot, -} - -#[derive(Clone, Debug)] -pub struct MemorySemanticProjectionObservation { - pub(crate) swarm_id: String, - pub(crate) partition: String, - pub(crate) obligation_id: String, - pub(crate) source_generation: u64, - pub(crate) canonical_model_hash: String, - pub(crate) canonical_content_set_hash: String, - pub(crate) status: String, - pub(crate) receipt_id: Option, - pub(crate) indexed_document_count: Option, - pub(crate) vector_dimensions: Option, - pub(crate) observed_source_at: String, - pub(crate) query_eligible_display_only: bool, -} - -impl MemorySemanticProjectionInput { - pub fn snapshot(&self) -> &super::EpiphanyMemoryGraphSnapshot { - &self.snapshot - } - - pub fn obligation(&self) -> &MemorySemanticProjectionObligation { - &self.obligation - } - - pub fn source_head(&self) -> &MemorySemanticProjectionSourceHead { - &self.authority.head - } -} - -pub fn observe_memory_semantic_projection( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, -) -> Result { - if input.authority.envelopes.is_empty() { - return Err(anyhow!( - "semantic projection observation requires canonical authority" - )); - } - validate_memory_semantic_projection_obligation(&input.obligation)?; - let envelopes = SingleFileMessagePackBackingStore::new(store_path.as_ref()).pull_all()?; - require_complete_modeling_basis( - &envelopes, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - let persisted_obligation = decode_one::( - &envelopes, - &input.obligation.obligation_id, - )? - .ok_or_else(|| anyhow!("semantic projection observation obligation disappeared"))?; - if persisted_obligation != input.obligation { - return Err(anyhow!( - "semantic projection observation obligation identity collision" - )); - } - for expected in &input.authority.envelopes { - let current = envelopes - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - .ok_or_else(|| anyhow!("semantic projection observation authority disappeared"))?; - if current != expected { - return Err(anyhow!( - "semantic projection observation authority advanced" - )); - } - } - let attempts = decode_all::(&envelopes)?; - let receipts = decode_all::(&envelopes)?; - let health = super::derive_memory_semantic_projection_health( - &input.obligation, - &input.authority.head, - &attempts, - &receipts, - )?; - let receipt = health - .receipt_id - .as_ref() - .and_then(|id| receipts.iter().find(|receipt| &receipt.receipt_id == id)); - if health.status == super::MemorySemanticProjectionHealthStatus::Ready { - let authenticated = load_memory_semantic_projection_success( - store_path.as_ref(), - &input.obligation, - &input.authority.head, - )? - .ok_or_else(|| { - anyhow!("semantic projection ready observation lacks authenticated success") - })?; - if receipt.is_none_or(|receipt| receipt != &authenticated) { - return Err(anyhow!( - "semantic projection ready observation receipt is not authentic" - )); - } - } - let observed_source_at = attempts - .iter() - .filter(|attempt| attempt.obligation_id == input.obligation.obligation_id) - .flat_map(|attempt| { - [ - attempt.started_at.as_str(), - attempt.completed_at.as_deref().unwrap_or(""), - ] - }) - .chain( - receipt - .into_iter() - .map(|receipt| receipt.indexed_at.as_str()), - ) - .filter(|value| !value.is_empty()) - .max_by_key(|value| chrono::DateTime::parse_from_rfc3339(value).ok()) - .unwrap_or(input.obligation.created_at.as_str()) - .to_string(); - let status = match health.status { - super::MemorySemanticProjectionHealthStatus::Pending => "pending", - super::MemorySemanticProjectionHealthStatus::Failed => "failed", - super::MemorySemanticProjectionHealthStatus::Stale => { - return Err(anyhow!( - "semantic projection observation input is not the current canonical head" - )); - } - super::MemorySemanticProjectionHealthStatus::Ready => "ready", - }; - let display_receipt = if health.status == super::MemorySemanticProjectionHealthStatus::Ready { - receipt - } else { - None - }; - Ok(MemorySemanticProjectionObservation { - swarm_id: input.obligation.swarm_id.clone(), - partition: input.obligation.partition.clone(), - obligation_id: input.obligation.obligation_id.clone(), - source_generation: input.obligation.source_generation, - canonical_model_hash: input.obligation.source_model_hash.clone(), - canonical_content_set_hash: input.obligation.canonical_content_set_hash.clone(), - status: status.to_string(), - receipt_id: display_receipt.map(|row| row.receipt_id.clone()), - indexed_document_count: display_receipt.map(|row| row.indexed_document_count), - vector_dimensions: display_receipt.map(|row| row.vector_dimensions), - observed_source_at, - query_eligible_display_only: health.query_eligible, - }) -} - -pub(crate) fn projection_scope_id(swarm_id: &str, partition: &str) -> Result { - if swarm_id.trim().is_empty() || partition != "modeling" { - return Err(anyhow!("semantic projection scope identity is invalid")); - } - Ok(format!( - "memory-semantic-scope-{partition}-{:x}", - Sha256::digest(format!("{swarm_id}|{partition}").as_bytes()) - )) -} - -pub(crate) fn memory_semantic_projector_store_id(store_path: &Path) -> Result { - let canonical = store_path.canonicalize().map_err(|error| { - anyhow!("semantic projector canonical store identity is unavailable: {error}") - })?; - let rendered = canonical.to_string_lossy(); - let identity = if cfg!(windows) { - rendered.to_lowercase() - } else { - rendered.into_owned() - }; - Ok(format!( - "memory-semantic-store-{:x}", - Sha256::digest(identity.as_bytes()) - )) -} - -pub fn load_memory_semantic_projection_success( - store_path: impl AsRef, - obligation: &MemorySemanticProjectionObligation, - head: &MemorySemanticProjectionSourceHead, -) -> Result> { - validate_memory_semantic_projection_obligation(obligation)?; - let envelopes = SingleFileMessagePackBackingStore::new(store_path.as_ref()).pull_all()?; - let attempts = decode_all::(&envelopes)?; - let receipts = decode_all::(&envelopes)?; - let health = - super::derive_memory_semantic_projection_health(obligation, head, &attempts, &receipts)?; - if health.status != super::MemorySemanticProjectionHealthStatus::Ready { - return Ok(None); - } - let receipt_id = health - .receipt_id - .ok_or_else(|| anyhow!("ready semantic projection health lost receipt identity"))?; - let receipt = receipts - .into_iter() - .find(|receipt| receipt.receipt_id == receipt_id) - .ok_or_else(|| anyhow!("ready semantic projection receipt disappeared"))?; - let scope_id = projection_scope_id(&obligation.swarm_id, &obligation.partition)?; - let claim = decode_one::(&envelopes, &scope_id)? - .ok_or_else(|| anyhow!("ready semantic projection lost its scope claim"))?; - validate_memory_semantic_projection_claim(&claim)?; - if claim.scope_id != scope_id { - return Err(anyhow!( - "semantic projection claim key disagrees with payload" - )); - } - authenticate_claim_authority(store_path.as_ref(), &claim)?; - if claim.status != "succeeded" - || claim.obligation_id != obligation.obligation_id - || receipt.claim_id != claim.claim_id - || receipt.claim_epoch != claim.epoch - { - return Err(anyhow!( - "ready semantic projection receipt is not authenticated by the succeeded scope claim" - )); - } - let attempt = decode_one::(&envelopes, &claim.attempt_id)? - .ok_or_else(|| anyhow!("ready semantic projection lost its claim attempt"))?; - validate_memory_semantic_projection_attempt(&attempt)?; - if attempt.status != "succeeded" || !attempt_authenticates_claim(&attempt, &claim) { - return Err(anyhow!( - "ready semantic projection claim is not authenticated by its succeeded attempt" - )); - } - Ok(Some(receipt)) -} - -pub fn load_memory_semantic_projection_readiness( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, -) -> Result> { - let receipt = load_memory_semantic_projection_success( - store_path, - &input.obligation, - &input.authority.head, - )?; - Ok( - receipt.map(|receipt| super::MemorySemanticProjectionReadiness { - obligation: input.obligation.clone(), - current: input.authority.head.clone(), - receipt, - }), - ) -} - -pub(crate) fn classify_memory_semantic_projection_for_pulse( - store_path: &Path, - input: &MemorySemanticProjectionInput, -) -> Result { - validate_memory_semantic_projection_obligation(&input.obligation)?; - let envelopes = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - if require_complete_modeling_basis( - &envelopes, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - ) - .is_err() - { - return Ok(super::MemorySemanticProjectorPulseClassification::Stale); - } - let persisted = decode_one::( - &envelopes, - &input.obligation.obligation_id, - )?; - if persisted.as_ref() != Some(&input.obligation) { - return Ok(super::MemorySemanticProjectorPulseClassification::Stale); - } - for expected in &input.authority.envelopes { - if envelopes - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(expected) - { - return Ok(super::MemorySemanticProjectorPulseClassification::Stale); - } - } - let scope_id = projection_scope_id(&input.obligation.swarm_id, &input.obligation.partition)?; - let current_claim = decode_one::(&envelopes, &scope_id)?; - if let Some(claim) = ¤t_claim { - validate_memory_semantic_projection_claim(&claim)?; - if claim.scope_id != scope_id { - return Err(anyhow!("semantic projector pulse claim key disagrees")); - } - if claim.obligation_id == input.obligation.obligation_id { - match claim.status.as_str() { - "running" => return Ok(super::MemorySemanticProjectorPulseClassification::Running), - _ => {} - } - } - } - let health = super::derive_memory_semantic_projection_health( - &input.obligation, - &input.authority.head, - &decode_all::(&envelopes)?, - &decode_all::(&envelopes)?, - )?; - let succeeded_predecessor = current_claim - .as_ref() - .map(|claim| { - authenticated_succeeded_predecessor(&envelopes, claim, &input.obligation.obligation_id) - }) - .transpose()? - .unwrap_or(false); - Ok(match health.status { - super::MemorySemanticProjectionHealthStatus::Pending => { - if succeeded_predecessor { - super::MemorySemanticProjectorPulseClassification::Repair - } else { - super::MemorySemanticProjectorPulseClassification::Pending - } - } - super::MemorySemanticProjectionHealthStatus::Failed => { - if succeeded_predecessor { - super::MemorySemanticProjectorPulseClassification::Repair - } else { - super::MemorySemanticProjectorPulseClassification::Failed - } - } - super::MemorySemanticProjectionHealthStatus::Ready => { - super::MemorySemanticProjectorPulseClassification::Ready - } - super::MemorySemanticProjectionHealthStatus::Stale => { - super::MemorySemanticProjectorPulseClassification::Stale - } - }) -} - -pub(crate) fn owned_running_memory_semantic_projection_claim( - store_path: &Path, - input: &MemorySemanticProjectionInput, - executor_id: &str, - executor_incarnation: &str, -) -> Result> { - let envelopes = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &envelopes, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - let scope_id = projection_scope_id(&input.obligation.swarm_id, &input.obligation.partition)?; - let Some(claim) = decode_one::(&envelopes, &scope_id)? else { - return Ok(None); - }; - validate_memory_semantic_projection_claim(&claim)?; - if claim.status != "running" - || claim.obligation_id != input.obligation.obligation_id - || claim.executor_id != executor_id - || claim.executor_incarnation != executor_incarnation - { - return Ok(None); - } - authenticate_claim_authority_from_envelopes(&envelopes, &claim)?; - for expected in &input.authority.envelopes { - if envelopes - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(expected) - { - return Err(anyhow!("owned running claim canonical authority advanced")); - } - } - Ok(Some(claim.claim_id)) -} - -#[allow(clippy::too_many_arguments)] -pub(crate) fn idunn_acquire_memory_semantic_projection_with_config( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - executor_id: &str, - executor_incarnation: &str, - purpose: &str, - idunn_incarnation: &str, - acquired_at: &str, - config: &super::MemorySemanticIndexConfig, -) -> Result { - let obligation = &input.obligation; - validate_memory_semantic_projection_obligation(obligation)?; - validate_identity_and_time(executor_id, acquired_at)?; - validate_opaque_identity(executor_incarnation, "executor incarnation")?; - validate_opaque_identity(idunn_incarnation, "issuer incarnation")?; - if !matches!(purpose, "execute" | "repair") { - return Err(anyhow!("semantic projector grant purpose is invalid")); - } - let store_path = store_path.as_ref(); - observe_memory_semantic_projection(store_path, input)?; - let cache = semantic_projector_cache(store_path)?; - let opening = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &opening, - &obligation.partition, - &obligation.source_commit_id, - &input.authority.envelopes, - )?; - let persisted = - decode_one::(&opening, &obligation.obligation_id)? - .ok_or_else(|| anyhow!("semantic projector grant requires persisted obligation"))?; - if persisted != *obligation { - return Err(anyhow!("semantic projector grant obligation advanced")); - } - ensure_not_before( - acquired_at, - &obligation.created_at, - "acquisition before obligation", - )?; - let scope_id = projection_scope_id(&obligation.swarm_id, &obligation.partition)?; - let current = decode_one::(&opening, &scope_id)?; - if let Some(claim) = ¤t { - validate_memory_semantic_projection_claim(claim)?; - if claim.scope_id != scope_id { - return Err(anyhow!( - "semantic projector scope key disagrees with claim payload" - )); - } - let attempt = decode_one::(&opening, &claim.attempt_id)? - .ok_or_else(|| anyhow!("semantic projector scope attempt disappeared"))?; - validate_memory_semantic_projection_attempt(&attempt)?; - if !attempt_authenticates_claim(&attempt, claim) || attempt.status != claim.status { - return Err(anyhow!( - "semantic projector scope claim and attempt disagree" - )); - } - if claim.status == "running" { - return Err(anyhow!("semantic projector scope is already running")); - } - ensure_not_before( - acquired_at, - claim.completed_at.as_deref().unwrap_or(&claim.claimed_at), - "acquisition before predecessor", - )?; - } - let succeeded_predecessor = current - .as_ref() - .map(|claim| { - authenticated_succeeded_predecessor(&opening, claim, &obligation.obligation_id) - }) - .transpose()? - .unwrap_or(false); - match purpose { - "execute" if succeeded_predecessor => { - return Err(anyhow!("execute grant cannot authorize succeeded repair")); - } - "repair" if !succeeded_predecessor => { - return Err(anyhow!("repair grant requires exact succeeded claim")); - } - _ => {} - } - let epoch = current.as_ref().map_or(1, |claim| claim.epoch + 1); - let grant_id = format!("memory-semantic-executor-grant-{}", uuid::Uuid::new_v4()); - let claim = running_claim( - &scope_id, - obligation, - executor_id, - executor_incarnation, - "executor_grant", - &grant_id, - epoch, - acquired_at, - ); - if obligation.partition != "modeling" - || config.qdrant_url.trim().is_empty() - || config.collection().trim().is_empty() - { - return Err(anyhow!("semantic projection physical namespace is invalid")); - } - let attempt = running_attempt(&claim, &config.qdrant_url, config.collection()); - let grant = MemorySemanticProjectorExecutorGrant { - schema_version: MEMORY_SEMANTIC_PROJECTOR_EXECUTOR_GRANT_SCHEMA_VERSION.to_string(), - grant_id: grant_id.clone(), - scope_id: scope_id.clone(), - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - obligation_id: obligation.obligation_id.clone(), - executor_id: executor_id.to_string(), - executor_incarnation: executor_incarnation.to_string(), - purpose: purpose.to_string(), - issuer_id: "idunn".to_string(), - issuer_incarnation: idunn_incarnation.to_string(), - status: "consumed".to_string(), - issued_at: acquired_at.to_string(), - consumed_at: Some(acquired_at.to_string()), - resulting_claim_id: Some(claim.claim_id.clone()), - resulting_claim_epoch: Some(claim.epoch), - predecessor_claim_id: current.as_ref().map(|row| row.claim_id.clone()), - predecessor_claim_epoch: current.as_ref().map(|row| row.epoch), - predecessor_claim_status: current - .as_ref() - .map_or("absent", |row| row.status.as_str()) - .to_string(), - }; - validate_memory_semantic_projector_executor_grant(&grant)?; - if opening.iter().any(|envelope| { - envelope.r#type == MemorySemanticProjectorExecutorGrant::TYPE - && envelope.key == grant.grant_id - }) { - return Err(anyhow!( - "semantic projector executor grant identity collision" - )); - } - let mut replacements = Vec::new(); - for authority in &input.authority.envelopes { - if authority.r#type == MemorySemanticProjectionObligation::TYPE - && authority.key == obligation.obligation_id - { - continue; - } - let persisted = opening - .iter() - .find(|row| row.r#type == authority.r#type && row.key == authority.key) - .ok_or_else(|| anyhow!("semantic projector acquisition authority disappeared"))?; - if persisted != authority { - return Err(anyhow!("semantic projector acquisition authority advanced")); - } - } - if current.is_some() { - exact_envelope( - &opening, - MemorySemanticProjectionClaim::TYPE, - &grant.scope_id, - )?; - let current = current.as_ref().expect("checked current claim"); - exact_envelope( - &opening, - MemorySemanticProjectionAttempt::TYPE, - ¤t.attempt_id, - )?; - } - replacements.push(cache.prepare_entry(&scope_id, &claim)?.0); - replacements.push(cache.prepare_entry(&attempt.attempt_id, &attempt)?.0); - replacements.push(cache.prepare_entry(&grant.grant_id, &grant)?.0); - if !SingleFileMessagePackBackingStore::new(store_path) - .replace_and_append_if_snapshot_unchanged(&opening, replacements)? - { - return Err(anyhow!( - "semantic projector acquisition lost its complete-basis snapshot fence" - )); - } - Ok(MemorySemanticProjectorAcquisition { grant, claim }) -} - -#[cfg(test)] -pub(crate) fn idunn_acquire_memory_semantic_projection( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - executor_id: &str, - executor_incarnation: &str, - purpose: &str, - idunn_incarnation: &str, - acquired_at: &str, -) -> Result { - idunn_acquire_memory_semantic_projection_with_config( - store_path, - input, - executor_id, - executor_incarnation, - purpose, - idunn_incarnation, - acquired_at, - &super::MemorySemanticIndexConfig::from_env(), - ) -} - -pub(crate) fn execute_memory_semantic_projection( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - claim_id: &str, - config: &super::MemorySemanticIndexConfig, -) -> Result { - if input.obligation.partition != "modeling" { - return Err(anyhow!( - "semantic projection obligation partition is invalid" - )); - } - let store_path = store_path.as_ref(); - let started_at = now_rfc3339(); - let (_, _, claim, attempt) = load_running_claim(store_path, claim_id)?; - if claim.obligation_id != input.obligation.obligation_id { - return Err(anyhow!( - "semantic projection claim does not bind input obligation" - )); - } - authenticate_claim_authority(store_path, &claim)?; - if attempt.physical_backend_url != config.qdrant_url - || attempt.collection_name != config.collection() - { - let error = anyhow!( - "semantic projection execution config disagrees with acquired physical namespace" - ); - let _ = fail_memory_semantic_projection_claim( - store_path, - &claim.claim_id, - &now_rfc3339(), - &format!("{error:#}"), - ); - return Err(error); - } - let raw_receipt = match super::semantic_index::index_memory_semantic_partition( - &input.snapshot, - &input.obligation.swarm_id, - &super::semantic_index::MemorySemanticProjectionNamespace { - obligation_id: claim.obligation_id.clone(), - claim_id: claim.claim_id.clone(), - claim_epoch: claim.epoch, - }, - &started_at, - config, - ) { - Ok(receipt) => receipt, - Err(error) => { - let _ = fail_memory_semantic_projection_claim( - store_path, - &claim.claim_id, - &now_rfc3339(), - &format!("{error:#}"), - ); - return Err(error); - } - }; - match succeed_memory_semantic_projection_claim( - store_path, - &claim.claim_id, - &input.authority, - raw_receipt, - &now_rfc3339(), - ) { - Ok(receipt) => Ok(receipt), - Err(error) => { - let _ = fail_memory_semantic_projection_claim( - store_path, - &claim.claim_id, - &now_rfc3339(), - &format!("terminal success refused: {error:#}"), - ); - Err(error) - } - } -} - -#[allow(clippy::too_many_arguments)] -#[allow(dead_code, clippy::too_many_arguments)] // Withheld behind sealed recovery evidence. -pub(crate) fn idunn_recover_memory_semantic_projection( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - expected_claim_id: &str, - replacement_executor_id: &str, - replacement_executor_incarnation: &str, - evidence: &IdunnSemanticRecoveryEvidence, - recovered_at: &str, -) -> Result<( - MemorySemanticProjectorRecoveryAuthorization, - MemorySemanticProjectionClaim, -)> { - validate_identity_and_time(replacement_executor_id, recovered_at)?; - validate_opaque_identity( - replacement_executor_incarnation, - "replacement executor incarnation", - )?; - validate_opaque_identity(&evidence.issuer_incarnation, "issuer incarnation")?; - validate_idunn_semantic_recovery_evidence(evidence)?; - if replacement_executor_incarnation != evidence.provider_incarnation { - return Err(anyhow!( - "recovery executor incarnation is not the observed provider incarnation" - )); - } - ensure_strictly_before( - &evidence.launch_lifecycle_receipt_completed_at, - &evidence.provider_heartbeat_at, - "provider heartbeat must follow managed-service launch receipt", - )?; - ensure_not_before( - recovered_at, - &evidence.provider_heartbeat_at, - "recovery precedes provider heartbeat", - )?; - let store_path = store_path.as_ref(); - validate_memory_semantic_projection_obligation(&input.obligation)?; - if evidence.canonical_store_id != memory_semantic_projector_store_id(store_path)? { - return Err(anyhow!( - "recovery evidence belongs to another canonical store" - )); - } - let cache = semantic_projector_cache(store_path)?; - let opening = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &opening, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - let current = decode_all::(&opening)? - .into_iter() - .find(|claim| claim.claim_id == expected_claim_id) - .ok_or_else(|| anyhow!("semantic projection recovery claim is missing"))?; - validate_memory_semantic_projection_claim(¤t)?; - if current.status != "running" { - return Err(anyhow!( - "semantic projection recovery requires exact running claim" - )); - } - authenticate_claim_authority_from_envelopes(&opening, ¤t)?; - let obligation = - decode_one::(&opening, ¤t.obligation_id)? - .ok_or_else(|| anyhow!("semantic projection recovery lost obligation"))?; - if obligation != input.obligation - || current.obligation_id != input.obligation.obligation_id - || current.scope_id - != projection_scope_id(&input.obligation.swarm_id, &input.obligation.partition)? - || evidence.scope_id != current.scope_id - || evidence.swarm_id != obligation.swarm_id - || evidence.partition != obligation.partition - || evidence.obligation_id != obligation.obligation_id - || evidence.claim_id != current.claim_id - || evidence.claim_epoch != current.epoch - || evidence.abandoned_executor_incarnation != current.executor_incarnation - { - return Err(anyhow!( - "recovery evidence does not bind exact canonical claim input" - )); - } - for expected in &input.authority.envelopes { - let persisted = opening - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - .ok_or_else(|| anyhow!("recovery canonical input authority disappeared"))?; - if persisted != expected { - return Err(anyhow!("recovery canonical input authority advanced")); - } - } - let old_attempt = decode_one::(&opening, ¤t.attempt_id)? - .ok_or_else(|| anyhow!("semantic projection recovery lost running attempt"))?; - validate_memory_semantic_projection_attempt(&old_attempt)?; - if old_attempt.status != "running" || !attempt_authenticates_claim(&old_attempt, ¤t) { - return Err(anyhow!( - "semantic projection recovery running attempt disagrees" - )); - } - ensure_not_before(recovered_at, ¤t.claimed_at, "recovery before claim")?; - let authorization_id = format!( - "memory-semantic-recovery-authorization-{:x}", - Sha256::digest( - format!( - "{}|{}|{}|{}", - evidence.canonical_store_id, - evidence.managed_service_policy_digest, - evidence.launch_lifecycle_receipt_digest, - evidence.provider_heartbeat_digest - ) - .as_bytes() - ) - ); - if opening.iter().any(|row| { - row.r#type == MemorySemanticProjectorRecoveryAuthorization::TYPE - && row.key == authorization_id - }) { - return Err(anyhow!("semantic recovery evidence was already consumed")); - } - let next = running_claim( - ¤t.scope_id, - &obligation, - replacement_executor_id, - replacement_executor_incarnation, - "recovery_authorization", - &authorization_id, - current.epoch + 1, - recovered_at, - ); - let next_attempt = running_attempt( - &next, - &old_attempt.physical_backend_url, - &old_attempt.collection_name, - ); - let failed_attempt = MemorySemanticProjectionAttempt { - completed_at: Some(recovered_at.to_string()), - status: "failed".to_string(), - error: Some("superseded by authenticated fenced recovery".to_string()), - ..old_attempt.clone() - }; - let authorization = MemorySemanticProjectorRecoveryAuthorization { - schema_version: MEMORY_SEMANTIC_PROJECTOR_RECOVERY_AUTHORIZATION_SCHEMA_VERSION.to_string(), - authorization_id: authorization_id.clone(), - scope_id: current.scope_id.clone(), - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - obligation_id: obligation.obligation_id.clone(), - claim_id: current.claim_id.clone(), - claim_epoch: current.epoch, - attempt_id: current.attempt_id.clone(), - abandoned_executor_id: current.executor_id.clone(), - abandoned_executor_incarnation: current.executor_incarnation.clone(), - replacement_executor_id: replacement_executor_id.to_string(), - replacement_executor_incarnation: replacement_executor_incarnation.to_string(), - issuer_id: "idunn".to_string(), - issuer_incarnation: evidence.issuer_incarnation.clone(), - managed_service_policy_id: evidence.managed_service_policy_id.clone(), - managed_service_policy_digest: evidence.managed_service_policy_digest.clone(), - launch_lifecycle_receipt_id: evidence.launch_lifecycle_receipt_id.clone(), - launch_lifecycle_receipt_digest: evidence.launch_lifecycle_receipt_digest.clone(), - launch_lifecycle_receipt_completed_at: evidence - .launch_lifecycle_receipt_completed_at - .clone(), - provider_heartbeat_id: evidence.provider_heartbeat_id.clone(), - provider_heartbeat_digest: evidence.provider_heartbeat_digest.clone(), - provider_incarnation: evidence.provider_incarnation.clone(), - provider_heartbeat_at: evidence.provider_heartbeat_at.clone(), - canonical_store_id: evidence.canonical_store_id.clone(), - startup_correlation_id: evidence.startup_correlation_id.clone(), - status: "consumed".to_string(), - issued_at: recovered_at.to_string(), - consumed_at: Some(recovered_at.to_string()), - resulting_claim_id: Some(next.claim_id.clone()), - resulting_claim_epoch: Some(next.epoch), - }; - validate_memory_semantic_projector_recovery_authorization(&authorization)?; - let mut replacements = vec![ - cache.prepare_entry(¤t.scope_id, &next)?.0, - cache - .prepare_entry(&failed_attempt.attempt_id, &failed_attempt)? - .0, - cache - .prepare_entry(&next_attempt.attempt_id, &next_attempt)? - .0, - cache - .prepare_entry(&authorization.authorization_id, &authorization)? - .0, - ]; - let authority_expected = input - .authority - .envelopes - .iter() - .filter(|row| { - !matches!( - row.r#type.as_str(), - "gamecult.epiphany.memory_semantic_projection_obligation" - | "gamecult.epiphany.memory_semantic_projection_claim" - | "gamecult.epiphany.memory_semantic_projection_attempt" - ) - }) - .cloned() - .collect::>(); - replacements.extend(authority_expected.iter().cloned()); - terminal_or_recovery_cas( - store_path, - &opening, - ¤t, - &old_attempt, - replacements, - &authority_expected, - )?; - Ok((authorization, next)) -} - -pub(crate) fn fail_memory_semantic_projection_claim( - store_path: impl AsRef, - claim_id: &str, - completed_at: &str, - error: &str, -) -> Result { - if error.trim().is_empty() { - return Err(anyhow!("semantic projection failure requires an error")); - } - chrono::DateTime::parse_from_rfc3339(completed_at) - .map_err(|_| anyhow!("semantic projection completion time must be RFC3339"))?; - let store_path = store_path.as_ref(); - let (cache, opening, claim, attempt) = load_running_claim(store_path, claim_id)?; - ensure_not_before(completed_at, &claim.claimed_at, "failure before claim")?; - let terminal_claim = MemorySemanticProjectionClaim { - status: "failed".to_string(), - completed_at: Some(completed_at.to_string()), - ..claim.clone() - }; - let terminal_attempt = MemorySemanticProjectionAttempt { - status: "failed".to_string(), - completed_at: Some(completed_at.to_string()), - error: Some(error.to_string()), - ..attempt.clone() - }; - terminal_or_recovery_cas( - store_path, - &opening, - &claim, - &attempt, - vec![ - cache.prepare_entry(&claim.scope_id, &terminal_claim)?.0, - cache - .prepare_entry(&attempt.attempt_id, &terminal_attempt)? - .0, - ], - &[], - )?; - Ok(terminal_claim) -} - -pub(crate) fn succeed_memory_semantic_projection_claim( - store_path: impl AsRef, - claim_id: &str, - authority: &MemorySemanticProjectionAuthoritySnapshot, - receipt: MemorySemanticIndexReceipt, - completed_at: &str, -) -> Result { - chrono::DateTime::parse_from_rfc3339(completed_at) - .map_err(|_| anyhow!("semantic projection completion time must be RFC3339"))?; - if authority.envelopes.is_empty() { - return Err(anyhow!( - "semantic projection success requires canonical authority envelopes" - )); - } - let store_path = store_path.as_ref(); - let (cache, opening, claim, attempt) = load_running_claim(store_path, claim_id)?; - ensure_not_before(completed_at, &claim.claimed_at, "success before claim")?; - let obligation = - decode_one::(&opening, &claim.obligation_id)? - .ok_or_else(|| anyhow!("semantic projection success lost obligation"))?; - require_complete_modeling_basis( - &opening, - &obligation.partition, - &obligation.source_commit_id, - &authority.envelopes, - )?; - ensure_not_before( - &receipt.indexed_at, - &claim.claimed_at, - "index receipt before claim", - )?; - ensure_not_before( - completed_at, - &receipt.indexed_at, - "success before index receipt", - )?; - if receipt.obligation_id != claim.obligation_id - || receipt.claim_id != claim.claim_id - || receipt.claim_epoch != claim.epoch - { - return Err(anyhow!( - "semantic projection result belongs to a different physical claim namespace" - )); - } - let receipt = bind_memory_semantic_index_receipt(receipt, &obligation)?; - if !memory_semantic_projection_terminal_success(&obligation, &authority.head, &receipt) { - return Err(anyhow!( - "semantic projection success no longer matches canonical source head" - )); - } - let terminal_claim = MemorySemanticProjectionClaim { - status: "succeeded".to_string(), - completed_at: Some(completed_at.to_string()), - ..claim.clone() - }; - let terminal_attempt = MemorySemanticProjectionAttempt { - status: "succeeded".to_string(), - completed_at: Some(completed_at.to_string()), - error: None, - ..attempt.clone() - }; - let replacements = vec![ - cache.prepare_entry(&claim.scope_id, &terminal_claim)?.0, - cache - .prepare_entry(&attempt.attempt_id, &terminal_attempt)? - .0, - cache.prepare_entry(&receipt.receipt_id, &receipt)?.0, - ]; - for authority_envelope in &authority.envelopes { - let current = opening - .iter() - .find(|candidate| { - candidate.r#type == authority_envelope.r#type - && candidate.key == authority_envelope.key - }) - .ok_or_else(|| anyhow!("canonical projection authority envelope disappeared"))?; - if current != authority_envelope { - return Err(anyhow!("canonical projection authority head advanced")); - } - } - if !SingleFileMessagePackBackingStore::new(store_path) - .replace_and_append_if_snapshot_unchanged(&opening, replacements)? - { - return Err(anyhow!( - "semantic projection success lost its complete-basis snapshot fence" - )); - } - Ok(receipt) -} - -pub(crate) fn validate_memory_semantic_projection_claim( - claim: &MemorySemanticProjectionClaim, -) -> Result<()> { - if claim.schema_version != MEMORY_SEMANTIC_PROJECTION_CLAIM_SCHEMA_VERSION - || claim.scope_id.trim().is_empty() - || claim.claim_id.trim().is_empty() - || claim.obligation_id.trim().is_empty() - || claim.attempt_id.trim().is_empty() - || claim.executor_id.trim().is_empty() - || !is_opaque_identity(&claim.executor_incarnation) - || !matches!( - claim.authority_kind.as_str(), - "executor_grant" | "recovery_authorization" - ) - || !is_opaque_identity(&claim.authority_id) - || claim.epoch == 0 - || chrono::DateTime::parse_from_rfc3339(&claim.claimed_at).is_err() - { - return Err(anyhow!("semantic projection claim is invalid")); - } - match claim.status.as_str() { - "running" if claim.completed_at.is_none() => Ok(()), - "failed" | "succeeded" - if claim - .completed_at - .as_deref() - .is_some_and(|time| chrono::DateTime::parse_from_rfc3339(time).is_ok()) => - { - Ok(()) - } - _ => Err(anyhow!( - "semantic projection claim terminal fields disagree" - )), - } -} - -pub fn validate_memory_semantic_projector_executor_grant( - grant: &MemorySemanticProjectorExecutorGrant, -) -> Result<()> { - let consumed = grant.status == "consumed" - && grant.consumed_at.as_deref().is_some_and(valid_rfc3339) - && grant - .resulting_claim_id - .as_deref() - .is_some_and(is_opaque_identity) - && grant.resulting_claim_epoch.is_some_and(|epoch| epoch > 0); - if grant.schema_version != MEMORY_SEMANTIC_PROJECTOR_EXECUTOR_GRANT_SCHEMA_VERSION - || !grant - .grant_id - .starts_with("memory-semantic-executor-grant-") - || !is_opaque_identity(&grant.grant_id) - || !is_opaque_identity(&grant.scope_id) - || !is_opaque_identity(&grant.swarm_id) - || grant.partition != "modeling" - || !is_opaque_identity(&grant.obligation_id) - || !is_opaque_identity(&grant.executor_id) - || !is_opaque_identity(&grant.executor_incarnation) - || !matches!(grant.purpose.as_str(), "execute" | "repair") - || grant.issuer_id != "idunn" - || !is_opaque_identity(&grant.issuer_incarnation) - || !valid_rfc3339(&grant.issued_at) - || grant.consumed_at.as_deref() != Some(grant.issued_at.as_str()) - || !consumed - || !matches!( - grant.predecessor_claim_status.as_str(), - "absent" | "failed" | "succeeded" - ) - || (grant.predecessor_claim_status == "absent" - && (grant.predecessor_claim_id.is_some() || grant.predecessor_claim_epoch.is_some())) - || (grant.predecessor_claim_status != "absent" - && !(grant - .predecessor_claim_id - .as_deref() - .is_some_and(is_opaque_identity) - && grant.predecessor_claim_epoch.is_some_and(|epoch| epoch > 0))) - || (grant.predecessor_claim_status == "absent" && grant.resulting_claim_epoch != Some(1)) - || grant - .predecessor_claim_epoch - .is_some_and(|epoch| grant.resulting_claim_epoch != Some(epoch + 1)) - || (grant.purpose == "repair" && grant.predecessor_claim_status != "succeeded") - || (grant.purpose == "execute" && grant.predecessor_claim_status == "succeeded") - { - return Err(anyhow!("semantic projector executor grant is invalid")); - } - Ok(()) -} - -pub fn validate_memory_semantic_projector_recovery_authorization( - authorization: &MemorySemanticProjectorRecoveryAuthorization, -) -> Result<()> { - let consumed = authorization.status == "consumed" - && authorization - .consumed_at - .as_deref() - .is_some_and(valid_rfc3339) - && authorization - .resulting_claim_id - .as_deref() - .is_some_and(is_opaque_identity) - && authorization - .resulting_claim_epoch - .is_some_and(|epoch| epoch > authorization.claim_epoch); - if authorization.schema_version - != MEMORY_SEMANTIC_PROJECTOR_RECOVERY_AUTHORIZATION_SCHEMA_VERSION - || !authorization - .authorization_id - .starts_with("memory-semantic-recovery-authorization-") - || !is_opaque_identity(&authorization.authorization_id) - || !is_opaque_identity(&authorization.scope_id) - || !is_opaque_identity(&authorization.swarm_id) - || authorization.partition != "modeling" - || !is_opaque_identity(&authorization.obligation_id) - || !is_opaque_identity(&authorization.claim_id) - || authorization.claim_epoch == 0 - || !is_opaque_identity(&authorization.attempt_id) - || !is_opaque_identity(&authorization.abandoned_executor_id) - || !is_opaque_identity(&authorization.abandoned_executor_incarnation) - || !is_opaque_identity(&authorization.replacement_executor_id) - || !is_opaque_identity(&authorization.replacement_executor_incarnation) - || authorization.issuer_id != "idunn" - || !is_opaque_identity(&authorization.issuer_incarnation) - || !is_opaque_identity(&authorization.managed_service_policy_id) - || !is_opaque_identity(&authorization.managed_service_policy_digest) - || !is_opaque_identity(&authorization.launch_lifecycle_receipt_id) - || !is_opaque_identity(&authorization.launch_lifecycle_receipt_digest) - || !valid_rfc3339(&authorization.launch_lifecycle_receipt_completed_at) - || !is_opaque_identity(&authorization.provider_heartbeat_id) - || !is_opaque_identity(&authorization.provider_heartbeat_digest) - || !is_opaque_identity(&authorization.provider_incarnation) - || !valid_rfc3339(&authorization.provider_heartbeat_at) - || !is_opaque_identity(&authorization.canonical_store_id) - || !is_opaque_identity(&authorization.startup_correlation_id) - || authorization.startup_correlation_id != authorization.launch_lifecycle_receipt_id - || authorization.replacement_executor_incarnation != authorization.provider_incarnation - || authorization.provider_incarnation == authorization.abandoned_executor_incarnation - || !strictly_before( - &authorization.launch_lifecycle_receipt_completed_at, - &authorization.provider_heartbeat_at, - ) - || !not_before( - authorization.consumed_at.as_deref().unwrap_or(""), - &authorization.provider_heartbeat_at, - ) - || !valid_rfc3339(&authorization.issued_at) - || authorization.consumed_at.as_deref() != Some(authorization.issued_at.as_str()) - || !consumed - { - return Err(anyhow!( - "semantic projector recovery authorization is invalid" - )); - } - Ok(()) -} - -pub fn validate_memory_semantic_physical_retirement_obligation( - obligation: &MemorySemanticPhysicalRetirementObligation, -) -> Result<()> { - if obligation.schema_version != MEMORY_SEMANTIC_PHYSICAL_RETIREMENT_OBLIGATION_SCHEMA_VERSION - || !obligation - .retirement_id - .starts_with("memory-semantic-physical-retirement-") - || !is_opaque_identity(&obligation.retirement_id) - || !is_opaque_identity(&obligation.scope_id) - || !is_opaque_identity(&obligation.swarm_id) - || obligation.partition != "modeling" - || !is_opaque_identity(&obligation.obligation_id) - || !is_opaque_identity(&obligation.attempt_id) - || !is_opaque_identity(&obligation.claim_id) - || obligation.claim_epoch == 0 - || obligation.physical_backend_url.trim().is_empty() - || obligation.collection_name.trim().is_empty() - || !obligation - .retention_authorization_sha256 - .starts_with("sha256:") - || obligation.retention_authorization_sha256.len() != 71 - || !valid_rfc3339(&obligation.authorized_at) - || obligation.private_state_exposed - { - return Err(anyhow!( - "semantic physical-retirement obligation is invalid" - )); - } - Ok(()) -} - -pub fn validate_memory_semantic_physical_retirement_receipt( - receipt: &MemorySemanticPhysicalRetirementReceipt, -) -> Result<()> { - if receipt.schema_version != MEMORY_SEMANTIC_PHYSICAL_RETIREMENT_RECEIPT_SCHEMA_VERSION - || !receipt - .receipt_id - .starts_with("memory-semantic-physical-retirement-receipt-") - || !is_opaque_identity(&receipt.receipt_id) - || !is_opaque_identity(&receipt.retirement_id) - || receipt.deleted_point_count != receipt.observed_point_count - || !valid_rfc3339(&receipt.completed_at) - || receipt.private_state_exposed - { - return Err(anyhow!("semantic physical-retirement receipt is invalid")); - } - Ok(()) -} - -fn retirement_authorization_digest(envelopes: &[CultCacheEnvelope]) -> String { - let mut rows = envelopes.to_vec(); - rows.sort_by(|left, right| { - left.r#type - .cmp(&right.r#type) - .then(left.key.cmp(&right.key)) - .then(left.payload.cmp(&right.payload)) - }); - let mut digest = Sha256::new(); - for row in rows { - digest.update((row.r#type.len() as u64).to_le_bytes()); - digest.update(row.r#type.as_bytes()); - digest.update((row.key.len() as u64).to_le_bytes()); - digest.update(row.key.as_bytes()); - digest.update((row.payload.len() as u64).to_le_bytes()); - digest.update(&row.payload); - } - format!("sha256:{:x}", digest.finalize()) -} - -fn physical_retirement_attempt_authority_rows( - snapshot: &[CultCacheEnvelope], - attempt: &MemorySemanticProjectionAttempt, -) -> Result> { - if let Some(grant) = - decode_one::(snapshot, &attempt.authority_id)? - { - validate_memory_semantic_projector_executor_grant(&grant)?; - if grant.obligation_id != attempt.obligation_id - || grant.executor_id != attempt.executor_id - || grant.executor_incarnation != attempt.executor_incarnation - || grant.resulting_claim_id.as_deref() != Some(attempt.claim_id.as_str()) - || grant.resulting_claim_epoch != Some(attempt.claim_epoch) - { - return Err(anyhow!( - "semantic physical-retirement attempt grant disagrees" - )); - } - return Ok(vec![exact_envelope( - snapshot, - MemorySemanticProjectorExecutorGrant::TYPE, - &grant.grant_id, - )?]); - } - if let Some(authorization) = - decode_one::(snapshot, &attempt.authority_id)? - { - validate_memory_semantic_projector_recovery_authorization(&authorization)?; - if authorization.obligation_id != attempt.obligation_id - || authorization.replacement_executor_id != attempt.executor_id - || authorization.replacement_executor_incarnation != attempt.executor_incarnation - || authorization.resulting_claim_id.as_deref() != Some(attempt.claim_id.as_str()) - || authorization.resulting_claim_epoch != Some(attempt.claim_epoch) - { - return Err(anyhow!( - "semantic physical-retirement attempt recovery authority disagrees" - )); - } - return Ok(vec![exact_envelope( - snapshot, - MemorySemanticProjectorRecoveryAuthorization::TYPE, - &authorization.authorization_id, - )?]); - } - Err(anyhow!( - "semantic physical-retirement attempt lost exact issuance authority" - )) -} - -pub fn authorize_memory_semantic_physical_retirements( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - retain_recent: usize, - authorized_at: &str, -) -> Result> { - if !valid_rfc3339(authorized_at) || input.authority.envelopes.is_empty() { - return Err(anyhow!( - "semantic physical retirement requires time and canonical authority" - )); - } - validate_memory_semantic_projection_obligation(&input.obligation)?; - let store_path = store_path.as_ref(); - let cache = semantic_projector_cache(store_path)?; - let snapshot = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &snapshot, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - for expected in &input.authority.envelopes { - if snapshot - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(expected) - { - return Err(anyhow!( - "semantic physical-retirement canonical authority advanced" - )); - } - } - let scope_id = projection_scope_id(&input.obligation.swarm_id, &input.obligation.partition)?; - if let Some(claim) = decode_one::(&snapshot, &scope_id)? { - validate_memory_semantic_projection_claim(&claim)?; - authenticate_claim_authority_from_envelopes(&snapshot, &claim)?; - let attempt = decode_one::(&snapshot, &claim.attempt_id)? - .ok_or_else(|| anyhow!("semantic physical retirement current attempt disappeared"))?; - validate_memory_semantic_projection_attempt(&attempt)?; - if !attempt_authenticates_claim(&attempt, &claim) || attempt.status != claim.status { - return Err(anyhow!( - "semantic physical retirement current claim and attempt disagree" - )); - } - if claim.status == "running" { - return Err(anyhow!( - "semantic physical retirement refuses running scope authority" - )); - } - } - let mut obligations = decode_all::(&snapshot)? - .into_iter() - .filter(|row| { - row.swarm_id == input.obligation.swarm_id && row.partition == input.obligation.partition - }) - .collect::>(); - obligations.sort_by(|left, right| { - left.source_generation - .cmp(&right.source_generation) - .then(left.obligation_id.cmp(&right.obligation_id)) - }); - if obligations.iter().any(|row| { - row.obligation_id != input.obligation.obligation_id - && !semantic_obligation_is_stale(row, &input.obligation) - }) { - return Err(anyhow!( - "semantic physical retirement refuses a non-stale generation" - )); - } - let recent = obligations - .iter() - .rev() - .take(retain_recent.max(1)) - .map(|row| row.obligation_id.clone()) - .collect::>(); - let attempts = decode_all::(&snapshot)?; - let existing = decode_all::(&snapshot)?; - let completed = decode_all::(&snapshot)? - .into_iter() - .map(|row| row.retirement_id) - .collect::>(); - let mut admitted = Vec::new(); - let mut changed = false; - let mut insertions = Vec::new(); - for obligation in obligations { - if !semantic_obligation_is_stale(&obligation, &input.obligation) - || recent.contains(&obligation.obligation_id) - { - continue; - } - let obligation_envelope = exact_envelope( - &snapshot, - MemorySemanticProjectionObligation::TYPE, - &obligation.obligation_id, - )?; - for attempt in attempts.iter().filter(|row| { - row.obligation_id == obligation.obligation_id - && row.status != "running" - && !row.physical_backend_url.trim().is_empty() - && !row.collection_name.trim().is_empty() - }) { - validate_memory_semantic_projection_attempt(attempt)?; - let attempt_envelope = exact_envelope( - &snapshot, - MemorySemanticProjectionAttempt::TYPE, - &attempt.attempt_id, - )?; - let mut authority_rows = vec![obligation_envelope.clone(), attempt_envelope.clone()]; - authority_rows.extend(physical_retirement_attempt_authority_rows( - &snapshot, attempt, - )?); - for receipt in decode_all::(&snapshot)? - .into_iter() - .filter(|receipt| { - receipt.obligation_id == attempt.obligation_id - && receipt.claim_id == attempt.claim_id - && receipt.claim_epoch == attempt.claim_epoch - }) - { - authority_rows.push(exact_envelope( - &snapshot, - MemorySemanticIndexReceipt::TYPE, - &receipt.receipt_id, - )?); - } - let digest = retirement_authorization_digest( - &input - .authority - .envelopes - .iter() - .cloned() - .chain(authority_rows.iter().cloned()) - .collect::>(), - ); - let retirement_id = format!( - "memory-semantic-physical-retirement-{:x}", - Sha256::digest(format!("{}|{}", attempt.attempt_id, digest).as_bytes()) - ); - if completed.contains(&retirement_id) { - continue; - } - let candidate = MemorySemanticPhysicalRetirementObligation { - schema_version: MEMORY_SEMANTIC_PHYSICAL_RETIREMENT_OBLIGATION_SCHEMA_VERSION - .to_string(), - retirement_id: retirement_id.clone(), - scope_id: scope_id.clone(), - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - obligation_id: obligation.obligation_id.clone(), - attempt_id: attempt.attempt_id.clone(), - claim_id: attempt.claim_id.clone(), - claim_epoch: attempt.claim_epoch, - physical_backend_url: attempt.physical_backend_url.clone(), - collection_name: attempt.collection_name.clone(), - retention_authorization_sha256: digest, - authorized_at: authorized_at.to_string(), - private_state_exposed: false, - }; - validate_memory_semantic_physical_retirement_obligation(&candidate)?; - if let Some(prior) = existing - .iter() - .find(|row| row.retirement_id == retirement_id) - { - let mut replay = candidate.clone(); - replay.authorized_at = prior.authorized_at.clone(); - if prior != &replay { - return Err(anyhow!("semantic physical-retirement identity collision")); - } - admitted.push(prior.clone()); - continue; - } - insertions.push(cache.prepare_entry(&retirement_id, &candidate)?.0); - admitted.push(candidate); - changed = true; - } - } - if !changed { - return Ok(admitted); - } - insertions.sort_by(|left, right| { - left.r#type - .cmp(&right.r#type) - .then(left.key.cmp(&right.key)) - }); - insertions.dedup_by(|left, right| left.r#type == right.r#type && left.key == right.key); - if !SingleFileMessagePackBackingStore::new(store_path) - .append_if_snapshot_unchanged(&snapshot, insertions)? - { - return Err(anyhow!( - "semantic physical-retirement authorization lost exact CAS" - )); - } - Ok(admitted) -} - -pub fn execute_memory_semantic_physical_retirement( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - retirement_id: &str, - config: &super::MemorySemanticIndexConfig, - completed_at: &str, -) -> Result { - let mut backend = - crate::semantic_backend::QdrantBackend::new(crate::semantic_backend::QdrantConfig { - url: config.qdrant_url.clone(), - api_key: config.qdrant_api_key.clone(), - timeout_ms: config.qdrant_timeout_ms, - })?; - execute_memory_semantic_physical_retirement_with_port( - store_path.as_ref(), - input, - retirement_id, - config, - completed_at, - &mut backend, - ) -} - -fn execute_memory_semantic_physical_retirement_with_port

( - store_path: &Path, - input: &MemorySemanticProjectionInput, - retirement_id: &str, - config: &super::MemorySemanticIndexConfig, - completed_at: &str, - port: &mut P, -) -> Result -where - P: MemorySemanticPhysicalRetirementPort, -{ - if !valid_rfc3339(completed_at) || input.authority.envelopes.is_empty() { - return Err(anyhow!( - "semantic physical retirement requires time and canonical authority" - )); - } - let cache = semantic_projector_cache(store_path)?; - let snapshot = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &snapshot, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - let retirement = - decode_one::(&snapshot, retirement_id)? - .ok_or_else(|| anyhow!("semantic physical-retirement obligation is missing"))?; - validate_memory_semantic_physical_retirement_obligation(&retirement)?; - let receipt_id = format!( - "memory-semantic-physical-retirement-receipt-{}", - retirement - .retirement_id - .trim_start_matches("memory-semantic-physical-retirement-") - ); - if let Some(receipt) = - decode_one::(&snapshot, &receipt_id)? - { - validate_memory_semantic_physical_retirement_receipt(&receipt)?; - if receipt.retirement_id != retirement.retirement_id { - return Err(anyhow!( - "semantic physical-retirement receipt identity collision" - )); - } - return Ok(receipt); - } - if retirement.physical_backend_url != config.qdrant_url - || retirement.partition != "modeling" - || retirement.collection_name != config.collection() - { - return Err(anyhow!( - "semantic physical-retirement namespace is not permitted by current projector policy" - )); - } - for expected in &input.authority.envelopes { - if snapshot - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(expected) - { - return Err(anyhow!( - "semantic physical-retirement canonical authority advanced" - )); - } - } - let source = - decode_one::(&snapshot, &retirement.obligation_id)? - .ok_or_else(|| anyhow!("semantic physical-retirement source obligation disappeared"))?; - let attempt = decode_one::(&snapshot, &retirement.attempt_id)? - .ok_or_else(|| anyhow!("semantic physical-retirement source attempt disappeared"))?; - validate_memory_semantic_projection_obligation(&source)?; - validate_memory_semantic_projection_attempt(&attempt)?; - if source.swarm_id != retirement.swarm_id - || source.partition != retirement.partition - || !semantic_obligation_is_stale(&source, &input.obligation) - || attempt.status == "running" - || attempt.obligation_id != source.obligation_id - || attempt.claim_id != retirement.claim_id - || attempt.claim_epoch != retirement.claim_epoch - || attempt.physical_backend_url != retirement.physical_backend_url - || attempt.collection_name != retirement.collection_name - { - return Err(anyhow!( - "semantic physical-retirement source authority disagrees" - )); - } - let mut source_rows = vec![ - exact_envelope( - &snapshot, - MemorySemanticProjectionObligation::TYPE, - &source.obligation_id, - )?, - exact_envelope( - &snapshot, - MemorySemanticProjectionAttempt::TYPE, - &attempt.attempt_id, - )?, - ]; - source_rows.extend(physical_retirement_attempt_authority_rows( - &snapshot, &attempt, - )?); - for index_receipt in decode_all::(&snapshot)? - .into_iter() - .filter(|index_receipt| { - index_receipt.obligation_id == attempt.obligation_id - && index_receipt.claim_id == attempt.claim_id - && index_receipt.claim_epoch == attempt.claim_epoch - }) - { - source_rows.push(exact_envelope( - &snapshot, - MemorySemanticIndexReceipt::TYPE, - &index_receipt.receipt_id, - )?); - } - let digest = retirement_authorization_digest( - &input - .authority - .envelopes - .iter() - .cloned() - .chain(source_rows.iter().cloned()) - .collect::>(), - ); - if digest != retirement.retention_authorization_sha256 { - return Err(anyhow!( - "semantic physical-retirement authorization digest disagrees" - )); - } - let claim_epoch = retirement.claim_epoch.to_string(); - let scope = [ - ("swarmId", retirement.swarm_id.as_str()), - ("partition", retirement.partition.as_str()), - ("obligationId", retirement.obligation_id.as_str()), - ("claimId", retirement.claim_id.as_str()), - ("claimEpoch", claim_epoch.as_str()), - ]; - let observed = port.point_ids_for_scope(&retirement.collection_name, &scope)?; - port.delete_points(&retirement.collection_name, &observed)?; - if !port - .point_ids_for_scope(&retirement.collection_name, &scope)? - .is_empty() - { - return Err(anyhow!( - "semantic physical retirement left points in the exact namespace" - )); - } - let receipt = MemorySemanticPhysicalRetirementReceipt { - schema_version: MEMORY_SEMANTIC_PHYSICAL_RETIREMENT_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id, - retirement_id: retirement.retirement_id.clone(), - observed_point_count: observed.len() as u64, - deleted_point_count: observed.len() as u64, - completed_at: completed_at.to_string(), - private_state_exposed: false, - }; - validate_memory_semantic_physical_retirement_receipt(&receipt)?; - exact_envelope( - &snapshot, - MemorySemanticPhysicalRetirementObligation::TYPE, - &retirement.retirement_id, - )?; - let receipt_envelope = cache.prepare_entry(&receipt.receipt_id, &receipt)?.0; - if !SingleFileMessagePackBackingStore::new(store_path) - .append_if_snapshot_unchanged(&snapshot, vec![receipt_envelope])? - { - return Err(anyhow!( - "semantic physical-retirement receipt lost exact CAS" - )); - } - Ok(receipt) -} - -pub fn retain_memory_semantic_projection_lifecycles( - store_path: impl AsRef, - input: &MemorySemanticProjectionInput, - retain_recent: usize, - retained_at: &str, -) -> Result> { - retain_memory_semantic_projection_lifecycles_with_before_commit( - store_path.as_ref(), - input, - retain_recent, - retained_at, - || Ok(()), - ) -} - -fn retain_memory_semantic_projection_lifecycles_with_before_commit( - store_path: &Path, - input: &MemorySemanticProjectionInput, - retain_recent: usize, - retained_at: &str, - before_commit: F, -) -> Result> -where - F: FnOnce() -> Result<()>, -{ - chrono::DateTime::parse_from_rfc3339(retained_at) - .map_err(|_| anyhow!("semantic projection retention time must be RFC3339"))?; - validate_memory_semantic_projection_obligation(&input.obligation)?; - if input.authority.envelopes.is_empty() { - return Err(anyhow!( - "semantic projection retention requires canonical authority" - )); - } - let cache = semantic_projector_cache(store_path)?; - let snapshot = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - require_complete_modeling_basis( - &snapshot, - &input.obligation.partition, - &input.obligation.source_commit_id, - &input.authority.envelopes, - )?; - let persisted = decode_one::( - &snapshot, - &input.obligation.obligation_id, - )? - .ok_or_else(|| anyhow!("semantic projection retention obligation disappeared"))?; - if persisted != input.obligation { - return Err(anyhow!( - "semantic projection retention obligation identity collision" - )); - } - for expected in &input.authority.envelopes { - if snapshot - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(expected) - { - return Err(anyhow!( - "semantic projection retention canonical authority advanced" - )); - } - } - let scope_id = projection_scope_id(&input.obligation.swarm_id, &input.obligation.partition)?; - let current_claim = decode_one::(&snapshot, &scope_id)?; - let mut preserved_obligation_ids = BTreeSet::from([input.obligation.obligation_id.clone()]); - if let Some(claim) = ¤t_claim { - validate_memory_semantic_projection_claim(claim)?; - if claim.scope_id != scope_id { - return Err(anyhow!( - "semantic projection retention claim key disagrees with payload" - )); - } - authenticate_claim_authority_from_envelopes(&snapshot, claim)?; - let attempt = decode_one::(&snapshot, &claim.attempt_id)? - .ok_or_else(|| anyhow!("semantic projection retention current attempt disappeared"))?; - validate_memory_semantic_projection_attempt(&attempt)?; - if !attempt_authenticates_claim(&attempt, claim) || attempt.status != claim.status { - return Err(anyhow!( - "semantic projection retention current claim and attempt disagree" - )); - } - if claim.status == "running" { - return Err(anyhow!( - "semantic projection retention refuses a running scope claim" - )); - } - preserved_obligation_ids.insert(claim.obligation_id.clone()); - } - - let mut obligations = decode_all::(&snapshot)? - .into_iter() - .filter(|obligation| { - obligation.swarm_id == input.obligation.swarm_id - && obligation.partition == input.obligation.partition - }) - .collect::>(); - for obligation in &obligations { - validate_memory_semantic_projection_obligation(obligation)?; - } - obligations.sort_by(|left, right| { - left.source_generation - .cmp(&right.source_generation) - .then(left.obligation_id.cmp(&right.obligation_id)) - }); - for obligation in &obligations { - if !preserved_obligation_ids.contains(&obligation.obligation_id) - && !semantic_obligation_is_stale(obligation, &input.obligation) - { - return Err(anyhow!( - "semantic projection retention refuses a non-stale generation" - )); - } - } - for obligation in obligations.iter().rev().take(retain_recent.max(1)) { - preserved_obligation_ids.insert(obligation.obligation_id.clone()); - } - - let attempts = decode_all::(&snapshot)?; - let receipts = decode_all::(&snapshot)?; - let grants = decode_all::(&snapshot)?; - let authorizations = decode_all::(&snapshot)?; - let physical_obligations = decode_all::(&snapshot)?; - let physical_receipts = decode_all::(&snapshot)?; - for retirement in &physical_obligations { - validate_memory_semantic_physical_retirement_obligation(retirement)?; - } - for receipt in &physical_receipts { - validate_memory_semantic_physical_retirement_receipt(receipt)?; - } - let mut retired_status_counts = BTreeMap::::new(); - let mut retired_obligation_ids = BTreeSet::new(); - for obligation in &obligations { - if preserved_obligation_ids.contains(&obligation.obligation_id) { - continue; - } - let obligation_attempts = attempts - .iter() - .filter(|attempt| attempt.obligation_id == obligation.obligation_id) - .collect::>(); - let obligation_receipts = receipts - .iter() - .filter(|receipt| receipt.obligation_id == obligation.obligation_id) - .collect::>(); - let obligation_grants = grants - .iter() - .filter(|grant| grant.obligation_id == obligation.obligation_id) - .collect::>(); - let obligation_authorizations = authorizations - .iter() - .filter(|authorization| authorization.obligation_id == obligation.obligation_id) - .collect::>(); - if !obligation_attempts.is_empty() { - let physically_closed = obligation_attempts.iter().all(|attempt| { - attempt.status != "running" - && !attempt.physical_backend_url.trim().is_empty() - && !attempt.collection_name.trim().is_empty() - && physical_obligations.iter().any(|retirement| { - retirement.attempt_id == attempt.attempt_id - && retirement.obligation_id == attempt.obligation_id - && retirement.claim_id == attempt.claim_id - && retirement.claim_epoch == attempt.claim_epoch - && retirement.physical_backend_url == attempt.physical_backend_url - && retirement.collection_name == attempt.collection_name - && physical_receipts.iter().any(|receipt| { - receipt.retirement_id == retirement.retirement_id - && receipt.deleted_point_count == receipt.observed_point_count - }) - }) - }); - if !physically_closed { - continue; - } - *retired_status_counts - .entry("physically_retired_attempted".to_string()) - .or_default() += 1; - retired_obligation_ids.insert(obligation.obligation_id.clone()); - continue; - } - if !obligation_receipts.is_empty() - || !obligation_grants.is_empty() - || !obligation_authorizations.is_empty() - { - continue; - } - *retired_status_counts - .entry("superseded_unattempted".to_string()) - .or_default() += 1; - retired_obligation_ids.insert(obligation.obligation_id.clone()); - } - if retired_obligation_ids.is_empty() { - return Ok(None); - } - - let mut deletions = snapshot - .iter() - .filter(|entry| match entry.r#type.as_str() { - MemorySemanticProjectionObligation::TYPE => retired_obligation_ids.contains(&entry.key), - MemorySemanticProjectionAttempt::TYPE => attempts.iter().any(|attempt| { - attempt.attempt_id == entry.key - && retired_obligation_ids.contains(&attempt.obligation_id) - }), - MemorySemanticIndexReceipt::TYPE => receipts.iter().any(|receipt| { - receipt.receipt_id == entry.key - && retired_obligation_ids.contains(&receipt.obligation_id) - }), - MemorySemanticProjectorExecutorGrant::TYPE => grants.iter().any(|grant| { - grant.grant_id == entry.key && retired_obligation_ids.contains(&grant.obligation_id) - }), - MemorySemanticProjectorRecoveryAuthorization::TYPE => { - authorizations.iter().any(|authorization| { - authorization.authorization_id == entry.key - && retired_obligation_ids.contains(&authorization.obligation_id) - }) - } - MemorySemanticPhysicalRetirementObligation::TYPE => { - physical_obligations.iter().any(|retirement| { - retirement.retirement_id == entry.key - && retired_obligation_ids.contains(&retirement.obligation_id) - }) - } - MemorySemanticPhysicalRetirementReceipt::TYPE => { - physical_receipts.iter().any(|receipt| { - receipt.receipt_id == entry.key - && physical_obligations.iter().any(|retirement| { - retirement.retirement_id == receipt.retirement_id - && retired_obligation_ids.contains(&retirement.obligation_id) - }) - }) - } - _ => false, - }) - .cloned() - .collect::>(); - deletions.sort_by(|left, right| { - left.r#type - .cmp(&right.r#type) - .then(left.key.cmp(&right.key)) - }); - let prior = decode_one::(&snapshot, &scope_id)?; - if let Some(head) = &prior { - validate_memory_semantic_projection_retention_head(head, &scope_id)?; - } - let mut retired_type_counts = prior - .as_ref() - .map(|head| head.retired_type_counts.clone()) - .unwrap_or_default(); - for entry in &deletions { - *retired_type_counts.entry(entry.r#type.clone()).or_default() += 1; - } - let mut cumulative_status_counts = prior - .as_ref() - .map(|head| head.retired_status_counts.clone()) - .unwrap_or_default(); - for (status, count) in retired_status_counts { - *cumulative_status_counts.entry(status).or_default() += count; - } - let prior_digest = prior - .as_ref() - .map(|head| head.retired_chain_digest.as_str()) - .unwrap_or("memory-semantic-projection-retention-root"); - let mut digest = Sha256::new(); - digest.update((prior_digest.len() as u64).to_le_bytes()); - digest.update(prior_digest.as_bytes()); - for entry in &deletions { - for bytes in [ - entry.r#type.as_bytes(), - entry.key.as_bytes(), - entry.payload.as_slice(), - ] { - digest.update((bytes.len() as u64).to_le_bytes()); - digest.update(bytes); - } - } - let head = MemorySemanticProjectionRetentionHead { - schema_version: MEMORY_SEMANTIC_PROJECTION_RETENTION_HEAD_SCHEMA_VERSION.to_string(), - scope_id: scope_id.clone(), - revision: prior.as_ref().map_or(1, |head| head.revision + 1), - retired_generation_count: prior - .as_ref() - .map_or(retired_obligation_ids.len() as u64, |head| { - head.retired_generation_count + retired_obligation_ids.len() as u64 - }), - retired_envelope_count: prior.as_ref().map_or(deletions.len() as u64, |head| { - head.retired_envelope_count + deletions.len() as u64 - }), - retired_type_counts, - retired_status_counts: cumulative_status_counts, - retired_chain_digest: format!("sha256:{:x}", digest.finalize()), - retained_at: retained_at.to_string(), - private_state_exposed: false, - }; - validate_memory_semantic_projection_retention_head(&head, &scope_id)?; - let (replacement, _) = cache.prepare_entry(&scope_id, &head)?; - before_commit()?; - if !SingleFileMessagePackBackingStore::new(store_path) - .replace_and_delete_if_snapshot_unchanged(&snapshot, vec![replacement], &deletions)? - { - return Err(anyhow!( - "semantic projection retention lost its full snapshot fence" - )); - } - Ok(Some(head)) -} - -fn semantic_obligation_is_stale( - candidate: &MemorySemanticProjectionObligation, - current: &MemorySemanticProjectionObligation, -) -> bool { - if candidate.swarm_id != current.swarm_id || candidate.partition != current.partition { - return false; - } - if current.partition == "modeling" { - // Modeling work is derived from a complete, exact set of keyed Mind - // document versions. There is no meaningful aggregate generation: any - // other content-addressed basis is stale relative to the freshly - // assembled current input. - candidate.obligation_id != current.obligation_id - } else { - candidate.source_generation < current.source_generation - } -} - -/// Proves that a Modeling input seals the complete keyed RepoModel visible in -/// the exact store snapshot used by the operation. Exact source-envelope -/// checks alone cannot see a disjoint insert, so they are insufficient for a -/// document-addressed concurrent Mind. -fn require_complete_modeling_basis( - snapshot: &[CultCacheEnvelope], - partition: &str, - expected_projection_digest: &str, - authority_envelopes: &[CultCacheEnvelope], -) -> Result<()> { - if partition != "modeling" { - return Ok(()); - } - let mut source_documents = Vec::new(); - for envelope in snapshot { - if crate::repo_model_documents::repo_model_write_key(envelope)?.is_some() { - source_documents.push(envelope); - } - } - source_documents - .sort_by(|left, right| (&left.r#type, &left.key).cmp(&(&right.r#type, &right.key))); - if source_documents.is_empty() { - // Historical synthetic projector fixtures predate keyed RepoModel - // authority and use human-readable commit ids. Current production - // Modeling inputs are content-addressed and must never take this path. - if !expected_projection_digest.starts_with("sha256:") { - return Ok(()); - } - return Err(anyhow!( - "Modeling projection has no complete keyed RepoModel basis" - )); - } - if source_documents.iter().any(|source| { - !authority_envelopes - .iter() - .any(|authority| authority == *source) - }) { - return Err(anyhow!( - "Modeling projection authority omits a current keyed RepoModel document" - )); - } - let source_versions = source_documents - .into_iter() - .map(|source| crate::EpiphanyMindDocumentVersion::from_envelope("epiphany-mind", source)) - .collect::>>()?; - let basis = crate::EpiphanyRepoModelBasis { - projection_digest: format!( - "sha256:{:x}", - Sha256::digest(rmp_serde::to_vec_named(&source_versions)?) - ), - source_documents: source_versions, - }; - basis.validate()?; - if basis.projection_digest != expected_projection_digest { - return Err(anyhow!( - "Modeling projection input does not seal the complete current keyed basis" - )); - } - Ok(()) -} - -fn validate_memory_semantic_projection_retention_head( - head: &MemorySemanticProjectionRetentionHead, - scope_id: &str, -) -> Result<()> { - if head.schema_version != MEMORY_SEMANTIC_PROJECTION_RETENTION_HEAD_SCHEMA_VERSION - || head.scope_id != scope_id - || head.revision == 0 - || head.retired_generation_count == 0 - || head.retired_envelope_count == 0 - || head.retired_type_counts.is_empty() - || head.retired_status_counts.is_empty() - || !head.retired_chain_digest.starts_with("sha256:") - || chrono::DateTime::parse_from_rfc3339(&head.retained_at).is_err() - || head.private_state_exposed - { - return Err(anyhow!("semantic projection retention head is invalid")); - } - Ok(()) -} - -pub(crate) fn semantic_projector_cache(store_path: &Path) -> Result { - let mut cache = CultCache::new(); - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(store_path)); - Ok(cache) -} - -fn running_claim( - scope_id: &str, - obligation: &MemorySemanticProjectionObligation, - executor_id: &str, - executor_incarnation: &str, - authority_kind: &str, - authority_id: &str, - epoch: u64, - claimed_at: &str, -) -> MemorySemanticProjectionClaim { - let fingerprint = format!( - "{}|{}|{}|{}|{}|{}|{}", - scope_id, - obligation.obligation_id, - executor_id, - executor_incarnation, - authority_kind, - authority_id, - epoch - ); - let claim_id = format!( - "memory-semantic-claim-{:x}", - Sha256::digest(fingerprint.as_bytes()) - ); - MemorySemanticProjectionClaim { - schema_version: MEMORY_SEMANTIC_PROJECTION_CLAIM_SCHEMA_VERSION.to_string(), - scope_id: scope_id.to_string(), - claim_id: claim_id.clone(), - obligation_id: obligation.obligation_id.clone(), - attempt_id: format!("memory-semantic-attempt-{claim_id}"), - executor_id: executor_id.to_string(), - executor_incarnation: executor_incarnation.to_string(), - authority_kind: authority_kind.to_string(), - authority_id: authority_id.to_string(), - epoch, - status: "running".to_string(), - claimed_at: claimed_at.to_string(), - completed_at: None, - } -} - -fn running_attempt( - claim: &MemorySemanticProjectionClaim, - physical_backend_url: &str, - collection_name: &str, -) -> MemorySemanticProjectionAttempt { - MemorySemanticProjectionAttempt { - schema_version: MEMORY_SEMANTIC_PROJECTION_ATTEMPT_SCHEMA_VERSION.to_string(), - attempt_id: claim.attempt_id.clone(), - obligation_id: claim.obligation_id.clone(), - started_at: claim.claimed_at.clone(), - completed_at: None, - status: "running".to_string(), - error: None, - claim_id: claim.claim_id.clone(), - claim_epoch: claim.epoch, - executor_id: claim.executor_id.clone(), - executor_incarnation: claim.executor_incarnation.clone(), - authority_id: claim.authority_id.clone(), - physical_backend_url: physical_backend_url.to_string(), - collection_name: collection_name.to_string(), - } -} - -fn load_running_claim( - store_path: &Path, - claim_id: &str, -) -> Result<( - CultCache, - Vec, - MemorySemanticProjectionClaim, - MemorySemanticProjectionAttempt, -)> { - let cache = semantic_projector_cache(store_path)?; - let opening = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - let claim = decode_all::(&opening)? - .into_iter() - .find(|claim| claim.claim_id == claim_id) - .ok_or_else(|| anyhow!("semantic projection claim is missing"))?; - validate_memory_semantic_projection_claim(&claim)?; - if claim.status != "running" { - return Err(anyhow!("semantic projection claim is not running")); - } - let attempt = decode_one::(&opening, &claim.attempt_id)? - .ok_or_else(|| anyhow!("semantic projection running attempt is missing"))?; - validate_memory_semantic_projection_attempt(&attempt)?; - if attempt.status != "running" || !attempt_authenticates_claim(&attempt, &claim) { - return Err(anyhow!("semantic projection attempt does not own claim")); - } - Ok((cache, opening, claim, attempt)) -} - -fn authenticate_claim_authority( - store_path: &Path, - claim: &MemorySemanticProjectionClaim, -) -> Result<()> { - let envelopes = SingleFileMessagePackBackingStore::new(store_path).pull_all()?; - authenticate_claim_authority_from_envelopes(&envelopes, claim)?; - if claim.authority_kind == "recovery_authorization" { - let auth = decode_one::( - &envelopes, - &claim.authority_id, - )? - .ok_or_else(|| anyhow!("semantic recovery authority disappeared"))?; - if auth.canonical_store_id != memory_semantic_projector_store_id(store_path)? { - return Err(anyhow!( - "semantic recovery authority belongs to another store" - )); - } - } - Ok(()) -} - -fn authenticate_claim_authority_from_envelopes( - envelopes: &[CultCacheEnvelope], - claim: &MemorySemanticProjectionClaim, -) -> Result<()> { - match claim.authority_kind.as_str() { - "executor_grant" => { - let grant = - decode_one::(envelopes, &claim.authority_id)? - .ok_or_else(|| { - anyhow!("semantic projection claim lost consumed executor authority") - })?; - validate_memory_semantic_projector_executor_grant(&grant)?; - if grant.grant_id != claim.authority_id - || grant.scope_id != claim.scope_id - || grant.obligation_id != claim.obligation_id - || grant.executor_id != claim.executor_id - || grant.executor_incarnation != claim.executor_incarnation - || grant.resulting_claim_id.as_deref() != Some(claim.claim_id.as_str()) - || grant.resulting_claim_epoch != Some(claim.epoch) - { - return Err(anyhow!( - "semantic projection claim executor authority disagrees" - )); - } - } - "recovery_authorization" => { - let auth = decode_one::( - envelopes, - &claim.authority_id, - )? - .ok_or_else(|| anyhow!("semantic projection claim lost consumed recovery authority"))?; - validate_memory_semantic_projector_recovery_authorization(&auth)?; - let abandoned_attempt = - decode_one::(envelopes, &auth.attempt_id)? - .ok_or_else(|| anyhow!("semantic recovery authority lost abandoned attempt"))?; - validate_memory_semantic_projection_attempt(&abandoned_attempt)?; - if auth.authorization_id != claim.authority_id - || auth.scope_id != claim.scope_id - || auth.obligation_id != claim.obligation_id - || auth.replacement_executor_id != claim.executor_id - || auth.replacement_executor_incarnation != claim.executor_incarnation - || auth.resulting_claim_id.as_deref() != Some(claim.claim_id.as_str()) - || auth.resulting_claim_epoch != Some(claim.epoch) - || abandoned_attempt.attempt_id != auth.attempt_id - || abandoned_attempt.obligation_id != auth.obligation_id - || abandoned_attempt.claim_id != auth.claim_id - || abandoned_attempt.claim_epoch != auth.claim_epoch - || abandoned_attempt.executor_id != auth.abandoned_executor_id - || abandoned_attempt.executor_incarnation != auth.abandoned_executor_incarnation - || abandoned_attempt.status != "failed" - || abandoned_attempt.completed_at.as_deref() != auth.consumed_at.as_deref() - { - return Err(anyhow!( - "semantic projection claim recovery authority disagrees" - )); - } - } - _ => { - return Err(anyhow!( - "semantic projection claim authority kind is invalid" - )); - } - } - Ok(()) -} - -fn attempt_authenticates_claim( - attempt: &MemorySemanticProjectionAttempt, - claim: &MemorySemanticProjectionClaim, -) -> bool { - attempt.attempt_id == claim.attempt_id - && attempt.obligation_id == claim.obligation_id - && attempt.claim_id == claim.claim_id - && attempt.claim_epoch == claim.epoch - && attempt.executor_id == claim.executor_id - && attempt.executor_incarnation == claim.executor_incarnation - && attempt.authority_id == claim.authority_id - && attempt.started_at == claim.claimed_at - && match (&attempt.completed_at, &claim.completed_at) { - (None, None) => true, - (Some(attempt_completed), Some(claim_completed)) => { - attempt_completed == claim_completed - } - _ => false, - } -} - -fn authenticated_succeeded_predecessor( - envelopes: &[CultCacheEnvelope], - claim: &MemorySemanticProjectionClaim, - obligation_id: &str, -) -> Result { - if claim.status != "succeeded" || claim.obligation_id != obligation_id { - return Ok(false); - } - authenticate_claim_authority_from_envelopes(envelopes, claim)?; - let attempt = decode_one::(envelopes, &claim.attempt_id)? - .ok_or_else(|| anyhow!("succeeded semantic predecessor lost its exact attempt"))?; - validate_memory_semantic_projection_attempt(&attempt)?; - if attempt.status != "succeeded" || !attempt_authenticates_claim(&attempt, claim) { - return Err(anyhow!( - "succeeded semantic predecessor is not authenticated by its exact attempt" - )); - } - Ok(true) -} - -fn terminal_or_recovery_cas( - store_path: &Path, - opening: &[CultCacheEnvelope], - claim: &MemorySemanticProjectionClaim, - attempt: &MemorySemanticProjectionAttempt, - mut replacements: Vec, - extra_expected: &[CultCacheEnvelope], -) -> Result<()> { - let obligation = exact_envelope( - opening, - "gamecult.epiphany.memory_semantic_projection_obligation", - &claim.obligation_id, - )?; - let claim_envelope = exact_envelope( - opening, - "gamecult.epiphany.memory_semantic_projection_claim", - &claim.scope_id, - )?; - let attempt_envelope = exact_envelope( - opening, - "gamecult.epiphany.memory_semantic_projection_attempt", - &attempt.attempt_id, - )?; - replacements.push(obligation.clone()); - let mut expected = vec![obligation, claim_envelope, attempt_envelope]; - expected.extend_from_slice(extra_expected); - if !SingleFileMessagePackBackingStore::new(store_path) - .compare_and_swap_batch(&expected, replacements)? - { - return Err(anyhow!( - "semantic projection terminal transition lost exact CAS" - )); - } - Ok(()) -} - -fn exact_envelope( - envelopes: &[CultCacheEnvelope], - type_name: &str, - key: &str, -) -> Result { - envelopes - .iter() - .find(|envelope| envelope.r#type == type_name && envelope.key == key) - .cloned() - .ok_or_else(|| anyhow!("missing {type_name} envelope {key:?}")) -} - -fn decode_one( - envelopes: &[CultCacheEnvelope], - key: &str, -) -> Result> { - envelopes - .iter() - .find(|envelope| envelope.r#type == T::TYPE && envelope.key == key) - .map(|envelope| { - rmp_serde::from_slice(&envelope.payload) - .map_err(|error| anyhow!("failed to decode {} {key:?}: {error}", T::TYPE)) - }) - .transpose() -} - -fn decode_all( - envelopes: &[CultCacheEnvelope], -) -> Result> { - envelopes - .iter() - .filter(|envelope| envelope.r#type == T::TYPE) - .map(|envelope| { - rmp_serde::from_slice(&envelope.payload).map_err(|error| { - anyhow!("failed to decode {} {:?}: {error}", T::TYPE, envelope.key) - }) - }) - .collect() -} - -fn validate_identity_and_time(identity: &str, time: &str) -> Result<()> { - if identity.trim().is_empty() { - return Err(anyhow!("semantic projection executor identity is empty")); - } - chrono::DateTime::parse_from_rfc3339(time) - .map_err(|_| anyhow!("semantic projection time must be RFC3339"))?; - Ok(()) -} - -fn validate_opaque_identity(value: &str, label: &str) -> Result<()> { - if !is_opaque_identity(value) { - return Err(anyhow!("semantic projection {label} is invalid")); - } - Ok(()) -} - -fn is_opaque_identity(value: &str) -> bool { - !value.is_empty() - && value.len() <= 256 - && value - .bytes() - .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':')) -} - -fn valid_rfc3339(value: &str) -> bool { - chrono::DateTime::parse_from_rfc3339(value).is_ok() -} - -fn validate_idunn_semantic_recovery_evidence( - evidence: &IdunnSemanticRecoveryEvidence, -) -> Result<()> { - for (value, label) in [ - (&evidence.issuer_incarnation, "issuer incarnation"), - ( - &evidence.managed_service_policy_id, - "managed service policy identity", - ), - ( - &evidence.managed_service_policy_digest, - "managed service policy digest", - ), - ( - &evidence.launch_lifecycle_receipt_id, - "launch lifecycle receipt identity", - ), - ( - &evidence.launch_lifecycle_receipt_digest, - "launch lifecycle receipt digest", - ), - ( - &evidence.provider_heartbeat_id, - "provider heartbeat identity", - ), - ( - &evidence.provider_heartbeat_digest, - "provider heartbeat digest", - ), - (&evidence.provider_incarnation, "provider incarnation"), - (&evidence.canonical_store_id, "canonical store identity"), - (&evidence.scope_id, "scope identity"), - (&evidence.swarm_id, "swarm identity"), - (&evidence.obligation_id, "obligation identity"), - (&evidence.claim_id, "claim identity"), - ( - &evidence.abandoned_executor_incarnation, - "abandoned executor incarnation", - ), - ( - &evidence.startup_correlation_id, - "startup correlation identity", - ), - ] { - validate_opaque_identity(value, label)?; - } - if !valid_rfc3339(&evidence.launch_lifecycle_receipt_completed_at) - || !valid_rfc3339(&evidence.provider_heartbeat_at) - || evidence.partition != "modeling" - || evidence.claim_epoch == 0 - || evidence.provider_incarnation == evidence.abandoned_executor_incarnation - || evidence.startup_correlation_id != evidence.launch_lifecycle_receipt_id - || !strictly_before( - &evidence.launch_lifecycle_receipt_completed_at, - &evidence.provider_heartbeat_at, - ) - { - return Err(anyhow!("semantic recovery evidence chronology is invalid")); - } - Ok(()) -} - -fn strictly_before(earlier: &str, later: &str) -> bool { - match ( - chrono::DateTime::parse_from_rfc3339(earlier), - chrono::DateTime::parse_from_rfc3339(later), - ) { - (Ok(earlier), Ok(later)) => earlier < later, - _ => false, - } -} - -fn not_before(later: &str, earlier: &str) -> bool { - match ( - chrono::DateTime::parse_from_rfc3339(later), - chrono::DateTime::parse_from_rfc3339(earlier), - ) { - (Ok(later), Ok(earlier)) => later >= earlier, - _ => false, - } -} - -fn ensure_strictly_before(earlier: &str, later: &str, message: &str) -> Result<()> { - if !strictly_before(earlier, later) { - return Err(anyhow!(message.to_string())); - } - Ok(()) -} - -fn ensure_not_before(later: &str, earlier: &str, message: &str) -> Result<()> { - let later = chrono::DateTime::parse_from_rfc3339(later) - .map_err(|_| anyhow!("semantic projection later time must be RFC3339"))?; - let earlier = chrono::DateTime::parse_from_rfc3339(earlier) - .map_err(|_| anyhow!("semantic projection earlier time must be RFC3339"))?; - if later < earlier { - return Err(anyhow!(message.to_string())); - } - Ok(()) -} - -fn now_rfc3339() -> String { - chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true) -} - -#[cfg(test)] -mod retention_tests { - use super::*; - use tempfile::tempdir; - - #[derive(Default)] - struct FakePhysicalRetirementPort { - point_ids: Vec, - observed_scopes: Vec>, - delete_calls: Vec<(String, Vec)>, - fail_delete: bool, - } - - impl MemorySemanticPhysicalRetirementPort for FakePhysicalRetirementPort { - fn point_ids_for_scope( - &mut self, - _collection: &str, - scope: &[(&str, &str)], - ) -> Result> { - self.observed_scopes.push( - scope - .iter() - .map(|(key, value)| ((*key).to_string(), (*value).to_string())) - .collect(), - ); - Ok(self.point_ids.clone()) - } - - fn delete_points(&mut self, collection: &str, point_ids: &[String]) -> Result<()> { - self.delete_calls - .push((collection.to_string(), point_ids.to_vec())); - if self.fail_delete { - return Err(anyhow!("fixture backend deletion failure")); - } - self.point_ids - .retain(|point_id| !point_ids.contains(point_id)); - Ok(()) - } - } - - fn obligation(swarm_id: &str, generation: u64) -> MemorySemanticProjectionObligation { - MemorySemanticProjectionObligation { - schema_version: super::super::MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION - .to_string(), - obligation_id: format!("memory-semantic-projection-modeling-{swarm_id}-{generation}"), - swarm_id: swarm_id.to_string(), - partition: "modeling".to_string(), - canonical_source_id: "runtime-model".to_string(), - source_commit_id: format!("commit-{generation}"), - graph_id: "repo-model".to_string(), - source_generation: generation, - source_model_hash: format!("sha256:model-{generation}"), - canonical_content_set_hash: format!("sha256:content-{generation}"), - projection_schema_version: super::super::SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - created_at: format!("2026-08-10T04:00:{generation:02}Z"), - } - } - - #[test] - fn modeling_staleness_is_exact_basis_identity_not_aggregate_generation() { - let current = obligation("swarm-state-driven", 1); - let mut other_basis = obligation("swarm-state-driven", 99); - other_basis.obligation_id = "memory-semantic-projection-modeling-other-basis".into(); - assert!(semantic_obligation_is_stale(&other_basis, ¤t)); - assert!(!semantic_obligation_is_stale(¤t, ¤t)); - } - - fn failed_lifecycle( - obligation: &MemorySemanticProjectionObligation, - epoch: u64, - ) -> ( - MemorySemanticProjectionClaim, - MemorySemanticProjectionAttempt, - MemorySemanticProjectorExecutorGrant, - ) { - let scope_id = projection_scope_id(&obligation.swarm_id, &obligation.partition).unwrap(); - let grant_id = format!( - "memory-semantic-executor-grant-{}-{}-{epoch}", - obligation.swarm_id, obligation.source_generation - ); - let mut claim = running_claim( - &scope_id, - obligation, - "semantic-executor", - &format!("executor-incarnation-{epoch}"), - "executor_grant", - &grant_id, - epoch, - &format!("2026-08-10T04:01:{epoch:02}Z"), - ); - claim.status = "failed".to_string(); - claim.completed_at = Some(format!("2026-08-10T04:02:{epoch:02}Z")); - let mut attempt = running_attempt(&claim, "http://qdrant", "epiphany_modeling_v1"); - attempt.status = "failed".to_string(); - attempt.completed_at = claim.completed_at.clone(); - attempt.error = Some("fixture failure".to_string()); - let grant = MemorySemanticProjectorExecutorGrant { - schema_version: MEMORY_SEMANTIC_PROJECTOR_EXECUTOR_GRANT_SCHEMA_VERSION.to_string(), - grant_id, - scope_id, - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - obligation_id: obligation.obligation_id.clone(), - executor_id: claim.executor_id.clone(), - executor_incarnation: claim.executor_incarnation.clone(), - purpose: "execute".to_string(), - issuer_id: "idunn".to_string(), - issuer_incarnation: "idunn-incarnation".to_string(), - status: "consumed".to_string(), - issued_at: claim.claimed_at.clone(), - consumed_at: Some(claim.claimed_at.clone()), - resulting_claim_id: Some(claim.claim_id.clone()), - resulting_claim_epoch: Some(claim.epoch), - predecessor_claim_id: None, - predecessor_claim_epoch: None, - predecessor_claim_status: "absent".to_string(), - }; - (claim, attempt, grant) - } - - fn input_for( - store: &Path, - current: &MemorySemanticProjectionObligation, - ) -> MemorySemanticProjectionInput { - let envelopes = SingleFileMessagePackBackingStore::new(store) - .pull_all() - .unwrap(); - let authority = envelopes - .into_iter() - .find(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == current.obligation_id - }) - .unwrap(); - MemorySemanticProjectionInput { - snapshot: super::super::EpiphanyMemoryGraphSnapshot { - graph_id: current.graph_id.clone(), - model_revision: current.source_generation, - model_hash: current.source_model_hash.clone(), - ..Default::default() - }, - obligation: current.clone(), - authority: MemorySemanticProjectionAuthoritySnapshot { - head: MemorySemanticProjectionSourceHead { - swarm_id: current.swarm_id.clone(), - partition: current.partition.clone(), - canonical_source_id: current.canonical_source_id.clone(), - source_commit_id: current.source_commit_id.clone(), - graph_id: current.graph_id.clone(), - source_generation: current.source_generation, - source_model_hash: current.source_model_hash.clone(), - canonical_content_set_hash: current.canonical_content_set_hash.clone(), - }, - envelopes: vec![authority], - }, - } - } - - fn keyed_input_for( - store: &Path, - current: &MemorySemanticProjectionObligation, - ) -> MemorySemanticProjectionInput { - let mut mind_cache = CultCache::new(); - mind_cache - .register_entry_type::() - .unwrap(); - mind_cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(store)); - mind_cache - .put( - crate::REPO_MODEL_IDENTITY_KEY, - &crate::EpiphanyRepoModelIdentityDocument { - schema_epoch: crate::REPO_MODEL_SCHEMA_EPOCH.into(), - graph_id: current.graph_id.clone(), - runtime_id: "runtime-semantic-retention-fixture".into(), - swarm_id: current.swarm_id.clone(), - workspace_id: "workspace-semantic-retention-fixture".into(), - body_binding_sha256: "sha256:semantic-retention-fixture".into(), - }, - ) - .unwrap(); - let envelopes = SingleFileMessagePackBackingStore::new(store) - .pull_all() - .unwrap(); - let repo_identity = envelopes - .iter() - .find(|entry| { - entry.r#type == crate::EpiphanyRepoModelIdentityDocument::TYPE - && entry.key == crate::REPO_MODEL_IDENTITY_KEY - }) - .unwrap() - .clone(); - let source_versions = vec![ - crate::EpiphanyMindDocumentVersion::from_envelope("epiphany-mind", &repo_identity) - .unwrap(), - ]; - let mut current = current.clone(); - current.source_commit_id = format!( - "sha256:{:x}", - Sha256::digest(rmp_serde::to_vec_named(&source_versions).unwrap()) - ); - let mut semantic_cache = semantic_projector_cache(store).unwrap(); - semantic_cache - .put(¤t.obligation_id, ¤t) - .unwrap(); - let authority = semantic_cache - .get_envelope::(¤t.obligation_id) - .unwrap() - .unwrap(); - MemorySemanticProjectionInput { - snapshot: super::super::EpiphanyMemoryGraphSnapshot { - graph_id: current.graph_id.clone(), - model_revision: current.source_generation, - model_hash: current.source_model_hash.clone(), - ..Default::default() - }, - obligation: current.clone(), - authority: MemorySemanticProjectionAuthoritySnapshot { - head: MemorySemanticProjectionSourceHead { - swarm_id: current.swarm_id.clone(), - partition: current.partition.clone(), - canonical_source_id: current.canonical_source_id.clone(), - source_commit_id: current.source_commit_id.clone(), - graph_id: current.graph_id.clone(), - source_generation: current.source_generation, - source_model_hash: current.source_model_hash.clone(), - canonical_content_set_hash: current.canonical_content_set_hash.clone(), - }, - envelopes: vec![authority, repo_identity], - }, - } - } - - #[test] - fn stale_modeling_input_cannot_ignore_a_disjoint_keyed_repo_model_insert() -> Result<()> { - let directory = tempdir()?; - let store = directory.path().join("semantic-current-basis.cc"); - let current = obligation("swarm-current-basis", 1); - let mut semantic_cache = semantic_projector_cache(&store)?; - semantic_cache.put(¤t.obligation_id, ¤t)?; - let stale_input = keyed_input_for(&store, ¤t); - - let domain = epiphany_state_model::EpiphanyMemoryDomain { - id: "domain-disjoint-phantom".into(), - profile: epiphany_state_model::EpiphanyMemoryProfile::RepoArchitecture, - title: "Disjoint keyed insert".into(), - lifecycle: epiphany_state_model::EpiphanyMemoryLifecycle::Accepted, - ..Default::default() - }; - let mut mind_cache = CultCache::new(); - mind_cache.register_entry_type::()?; - mind_cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&store)); - mind_cache.put( - &domain.id, - &crate::EpiphanyRepoModelDomainDocument::new(&domain)?, - )?; - - let before = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let acquisition = idunn_acquire_memory_semantic_projection( - &store, - &stale_input, - "semantic-executor", - "semantic-executor-incarnation", - "execute", - "idunn-incarnation", - "2026-08-10T05:00:00Z", - ) - .unwrap_err(); - assert!( - acquisition - .to_string() - .contains("Modeling projection authority omits") - ); - assert_eq!( - SingleFileMessagePackBackingStore::new(&store).pull_all()?, - before, - "stale acquisition must refuse byte-identically" - ); - - let retention = retain_memory_semantic_projection_lifecycles( - &store, - &stale_input, - 1, - "2026-08-10T05:01:00Z", - ) - .unwrap_err(); - assert!( - retention - .to_string() - .contains("Modeling projection authority omits") - ); - assert_eq!( - SingleFileMessagePackBackingStore::new(&store).pull_all()?, - before, - "stale retention must refuse byte-identically" - ); - Ok(()) - } - - #[test] - fn physical_retirement_is_policy_bound_receipted_and_then_logically_compactable() -> Result<()> - { - let directory = tempdir()?; - let store = directory.path().join("semantic.cc"); - let old = obligation("swarm-physical", 1); - let current = obligation("swarm-physical", 3); - let (_claim, attempt, grant) = failed_lifecycle(&old, 1); - let mut cache = semantic_projector_cache(&store)?; - cache.put(&old.obligation_id, &old)?; - cache.put(¤t.obligation_id, ¤t)?; - cache.put(&attempt.attempt_id, &attempt)?; - cache.put(&grant.grant_id, &grant)?; - let input = input_for(&store, ¤t); - let retirements = authorize_memory_semantic_physical_retirements( - &store, - &input, - 1, - "2026-08-10T09:00:00Z", - )?; - assert_eq!(retirements.len(), 1); - let retirement = &retirements[0]; - assert_eq!(retirement.attempt_id, attempt.attempt_id); - assert_eq!(retirement.physical_backend_url, "http://qdrant"); - assert_eq!(retirement.collection_name, "epiphany_modeling_v1"); - assert_eq!( - authorize_memory_semantic_physical_retirements( - &store, - &input, - 1, - "2026-08-10T09:00:30Z", - )?, - retirements, - "pending retirement authority must replay without a new timestamp identity" - ); - - let mut config = super::super::MemorySemanticIndexConfig::from_env(); - config.qdrant_url = "http://foreign-qdrant".into(); - config.modeling_collection = "epiphany_modeling_v1".into(); - let mut untouched = FakePhysicalRetirementPort { - point_ids: vec!["point-a".into()], - ..Default::default() - }; - let error = execute_memory_semantic_physical_retirement_with_port( - &store, - &input, - &retirement.retirement_id, - &config, - "2026-08-10T09:01:00Z", - &mut untouched, - ) - .unwrap_err(); - assert!(error.to_string().contains("not permitted")); - assert!(untouched.observed_scopes.is_empty()); - assert!(untouched.delete_calls.is_empty()); - - config.qdrant_url = "http://qdrant".into(); - let mut failing = FakePhysicalRetirementPort { - point_ids: vec!["point-a".into(), "point-b".into()], - fail_delete: true, - ..Default::default() - }; - assert!( - execute_memory_semantic_physical_retirement_with_port( - &store, - &input, - &retirement.retirement_id, - &config, - "2026-08-10T09:01:30Z", - &mut failing, - ) - .is_err() - ); - let after_failure = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - assert!(after_failure.iter().any(|row| { - row.r#type == MemorySemanticPhysicalRetirementObligation::TYPE - && row.key == retirement.retirement_id - })); - assert!( - !after_failure - .iter() - .any(|row| { row.r#type == MemorySemanticPhysicalRetirementReceipt::TYPE }) - ); - assert!( - retain_memory_semantic_projection_lifecycles( - &store, - &input, - 1, - "2026-08-10T09:01:31Z", - )? - .is_none(), - "backend failure must preserve logical retry authority" - ); - let mut backend = FakePhysicalRetirementPort { - point_ids: vec!["point-a".into(), "point-b".into()], - ..Default::default() - }; - let receipt = execute_memory_semantic_physical_retirement_with_port( - &store, - &input, - &retirement.retirement_id, - &config, - "2026-08-10T09:02:00Z", - &mut backend, - )?; - assert_eq!(receipt.observed_point_count, 2); - assert_eq!(receipt.deleted_point_count, 2); - assert_eq!(backend.delete_calls.len(), 1); - assert_eq!(backend.observed_scopes.len(), 2); - assert!( - backend.observed_scopes[0] - .contains(&("obligationId".into(), old.obligation_id.clone())) - ); - assert!( - backend.observed_scopes[0] - .contains(&("claimEpoch".into(), attempt.claim_epoch.to_string())) - ); - - let head = retain_memory_semantic_projection_lifecycles( - &store, - &input, - 1, - "2026-08-10T09:03:00Z", - )? - .expect("receipted physical namespace should permit logical compaction"); - assert_eq!( - head.retired_status_counts - .get("physically_retired_attempted"), - Some(&1) - ); - let after = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - assert!(!after.iter().any(|row| { - row.key == old.obligation_id - || row.key == attempt.attempt_id - || row.key == grant.grant_id - || row.key == retirement.retirement_id - || row.key == receipt.receipt_id - })); - assert!(after.iter().any(|row| row.key == current.obligation_id)); - Ok(()) - } - - #[test] - fn semantic_lifecycle_retention_preserves_current_chain_and_refuses_stale_snapshot() - -> Result<()> { - let directory = tempdir()?; - let store = directory.path().join("semantic.cc"); - let older_failed = obligation("swarm-a", 0); - let older_unattempted = obligation("swarm-a", 1); - let predecessor = obligation("swarm-a", 2); - let current = obligation("swarm-a", 3); - let unrelated = obligation("swarm-b", 1); - let (older_claim, older_attempt, older_grant) = failed_lifecycle(&older_failed, 1); - let (predecessor_claim, predecessor_attempt, predecessor_grant) = - failed_lifecycle(&predecessor, 1); - let mut cache = semantic_projector_cache(&store)?; - for obligation in [ - &older_failed, - &older_unattempted, - &predecessor, - ¤t, - &unrelated, - ] { - cache.put(&obligation.obligation_id, obligation)?; - } - cache.put(&older_attempt.attempt_id, &older_attempt)?; - cache.put(&older_grant.grant_id, &older_grant)?; - cache.put(&predecessor_attempt.attempt_id, &predecessor_attempt)?; - cache.put(&predecessor_grant.grant_id, &predecessor_grant)?; - cache.put(&predecessor_claim.scope_id, &predecessor_claim)?; - let input = input_for(&store, ¤t); - let opening = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let unrelated_before = opening - .iter() - .find(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == unrelated.obligation_id - }) - .cloned() - .unwrap(); - let raced = obligation("swarm-b", 2); - let error = retain_memory_semantic_projection_lifecycles_with_before_commit( - &store, - &input, - 1, - "2026-08-10T05:00:00Z", - || { - let mut race_cache = semantic_projector_cache(&store)?; - race_cache.put(&raced.obligation_id, &raced)?; - Ok(()) - }, - ) - .unwrap_err(); - assert!(error.to_string().contains("snapshot fence"), "{error:#}"); - let after_race = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - assert!(after_race.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == older_failed.obligation_id - })); - assert!(after_race.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == raced.obligation_id - })); - - let head = retain_memory_semantic_projection_lifecycles( - &store, - &input, - 1, - "2026-08-10T05:00:01Z", - )? - .expect("older semantic generations should retire"); - assert_eq!(head.retired_generation_count, 1); - assert_eq!(head.retired_status_counts.get("failed"), None); - assert_eq!( - head.retired_status_counts.get("superseded_unattempted"), - Some(&1) - ); - let after = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - assert!(!after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == older_unattempted.obligation_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == older_failed.obligation_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionAttempt::TYPE - && entry.key == older_attempt.attempt_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectorExecutorGrant::TYPE - && entry.key == older_grant.grant_id - })); - for preserved in [&predecessor.obligation_id, ¤t.obligation_id] { - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE && &entry.key == preserved - })); - } - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionClaim::TYPE - && entry.key == predecessor_claim.scope_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionAttempt::TYPE - && entry.key == predecessor_attempt.attempt_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectorExecutorGrant::TYPE - && entry.key == predecessor_grant.grant_id - })); - assert_eq!( - after.iter().find(|entry| { - entry.r#type == MemorySemanticProjectionObligation::TYPE - && entry.key == unrelated.obligation_id - }), - Some(&unrelated_before) - ); - assert!( - decode_one::(&after, &head.scope_id)?.is_none(), - "retention head must not deserialize as projection obligation" - ); - assert!(decode_one::(&after, &head.scope_id)?.is_some()); - assert!(decode_one::(&after, &head.scope_id)?.is_none()); - assert!(decode_one::(&after, &head.scope_id)?.is_none()); - assert!( - decode_one::(&after, &head.scope_id)?.is_none() - ); - assert!( - load_memory_semantic_projection_readiness(&store, &input)?.is_none(), - "retention head must not open semantic query readiness" - ); - let stable = after.clone(); - assert!( - retain_memory_semantic_projection_lifecycles( - &store, - &input, - 1, - "2026-08-10T05:00:02Z", - )? - .is_none() - ); - assert_eq!( - SingleFileMessagePackBackingStore::new(&store).pull_all()?, - stable - ); - let _ = older_claim; - Ok(()) - } - - #[test] - fn semantic_lifecycle_retention_preserves_exact_ready_chain() -> Result<()> { - let directory = tempdir()?; - let store = directory.path().join("semantic.cc"); - let older = obligation("swarm-ready", 1); - let current = obligation("swarm-ready", 2); - let (mut claim, mut attempt, grant) = failed_lifecycle(¤t, 1); - claim.status = "succeeded".to_string(); - attempt.status = "succeeded".to_string(); - attempt.error = None; - let receipt = MemorySemanticIndexReceipt { - schema_version: super::super::MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.to_string(), - receipt_id: "memory-semantic-index-ready-fixture".to_string(), - swarm_id: current.swarm_id.clone(), - partition: current.partition.clone(), - collection_name: "epiphany_modeling_v1".to_string(), - graph_id: current.graph_id.clone(), - model_revision: current.source_generation, - model_hash: current.source_model_hash.clone(), - embedding_provider_id: "ollama".to_string(), - embedding_model: "qwen3-embedding".to_string(), - vector_dimensions: 3, - indexed_document_count: 1, - deleted_document_count: 0, - canonical_content_set_hash: current.canonical_content_set_hash.clone(), - indexed_at: "2026-08-10T04:01:01Z".to_string(), - status: "ready".to_string(), - obligation_id: current.obligation_id.clone(), - canonical_source_id: current.canonical_source_id.clone(), - source_commit_id: current.source_commit_id.clone(), - source_generation: current.source_generation, - projection_schema_version: current.projection_schema_version.clone(), - claim_id: claim.claim_id.clone(), - claim_epoch: claim.epoch, - observed_vector_binding_root_sha256: "a".repeat(64), - }; - let mut cache = semantic_projector_cache(&store)?; - cache.put(&older.obligation_id, &older)?; - cache.put(¤t.obligation_id, ¤t)?; - cache.put(&grant.grant_id, &grant)?; - cache.put(&attempt.attempt_id, &attempt)?; - cache.put(&claim.scope_id, &claim)?; - cache.put(&receipt.receipt_id, &receipt)?; - let input = input_for(&store, ¤t); - let ready_before = load_memory_semantic_projection_readiness(&store, &input)? - .expect("fixture should open exact readiness"); - let head = retain_memory_semantic_projection_lifecycles( - &store, - &input, - 1, - "2026-08-10T07:00:00Z", - )? - .expect("older generation should retire"); - assert_eq!(head.retired_generation_count, 1); - let ready_after = load_memory_semantic_projection_readiness(&store, &input)? - .expect("retention must preserve exact readiness"); - assert_eq!(ready_after.receipt, ready_before.receipt); - let after = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionClaim::TYPE && entry.key == claim.scope_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectionAttempt::TYPE && entry.key == attempt.attempt_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticIndexReceipt::TYPE && entry.key == receipt.receipt_id - })); - assert!(after.iter().any(|entry| { - entry.r#type == MemorySemanticProjectorExecutorGrant::TYPE - && entry.key == grant.grant_id - })); - Ok(()) - } - - #[test] - fn semantic_lifecycle_retention_refuses_running_current_claim() -> Result<()> { - let directory = tempdir()?; - let store = directory.path().join("semantic.cc"); - let older = obligation("swarm-running", 1); - let current = obligation("swarm-running", 2); - let scope_id = projection_scope_id(¤t.swarm_id, ¤t.partition)?; - let grant_id = "memory-semantic-executor-grant-running"; - let claim = running_claim( - &scope_id, - ¤t, - "semantic-executor", - "executor-incarnation-running", - "executor_grant", - grant_id, - 1, - "2026-08-10T06:00:00Z", - ); - let attempt = running_attempt(&claim, "http://qdrant", "epiphany_mind_v1"); - let grant = MemorySemanticProjectorExecutorGrant { - schema_version: MEMORY_SEMANTIC_PROJECTOR_EXECUTOR_GRANT_SCHEMA_VERSION.to_string(), - grant_id: grant_id.to_string(), - scope_id: scope_id.clone(), - swarm_id: current.swarm_id.clone(), - partition: current.partition.clone(), - obligation_id: current.obligation_id.clone(), - executor_id: claim.executor_id.clone(), - executor_incarnation: claim.executor_incarnation.clone(), - purpose: "execute".to_string(), - issuer_id: "idunn".to_string(), - issuer_incarnation: "idunn-incarnation".to_string(), - status: "consumed".to_string(), - issued_at: claim.claimed_at.clone(), - consumed_at: Some(claim.claimed_at.clone()), - resulting_claim_id: Some(claim.claim_id.clone()), - resulting_claim_epoch: Some(claim.epoch), - predecessor_claim_id: None, - predecessor_claim_epoch: None, - predecessor_claim_status: "absent".to_string(), - }; - let mut cache = semantic_projector_cache(&store)?; - cache.put(&older.obligation_id, &older)?; - cache.put(¤t.obligation_id, ¤t)?; - cache.put(&grant.grant_id, &grant)?; - cache.put(&attempt.attempt_id, &attempt)?; - cache.put(&scope_id, &claim)?; - let input = input_for(&store, ¤t); - let opening = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let error = - retain_memory_semantic_projection_lifecycles(&store, &input, 1, "2026-08-10T06:00:01Z") - .unwrap_err(); - assert!(error.to_string().contains("running scope claim")); - assert_eq!( - SingleFileMessagePackBackingStore::new(&store).pull_all()?, - opening - ); - Ok(()) - } -} diff --git a/epiphany-core/src/memory_graph/semantic_projector_pulse.rs b/epiphany-core/src/memory_graph/semantic_projector_pulse.rs deleted file mode 100644 index 816c8039..00000000 --- a/epiphany-core/src/memory_graph/semantic_projector_pulse.rs +++ /dev/null @@ -1,430 +0,0 @@ -use super::MemorySemanticProjectionInput; -use anyhow::Result; -use std::sync::atomic::{AtomicBool, Ordering}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum MemorySemanticProjectorPulseClassification { - Pending, - Failed, - Repair, - Ready, - Running, - RunningOwned { claim_id: String }, - Stale, -} - -impl MemorySemanticProjectorPulseClassification { - fn automatic_purpose(&self) -> Option<&'static str> { - match self { - Self::Pending | Self::Failed => Some("execute"), - Self::Repair => Some("repair"), - Self::Ready | Self::Running | Self::RunningOwned { .. } | Self::Stale => None, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MemorySemanticProjectorPulseInspection { - pub scope_id: String, - pub classification: Option, - pub error: Option, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum MemorySemanticProjectorPulseStatus { - Idle, - Executed, - Contended, - Refused, - Busy, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MemorySemanticProjectorPulseOutcome { - pub status: MemorySemanticProjectorPulseStatus, - pub selected_scope_id: Option, - pub inspections: Vec, - pub error: Option, -} - -pub(crate) trait MemorySemanticProjectorPulsePort { - fn classify( - &self, - input: &MemorySemanticProjectionInput, - ) -> Result; - - /// `Ok(None)` means another pulse won the exact acquisition CAS. - fn acquire( - &self, - input: &MemorySemanticProjectionInput, - purpose: &str, - ) -> Result>; - - fn execute(&self, input: &MemorySemanticProjectionInput, claim_id: &str) -> Result<()>; -} - -pub(crate) struct MemorySemanticProjectorPulser

{ - pub(crate) port: P, - active: AtomicBool, -} - -impl

MemorySemanticProjectorPulser

-where - P: MemorySemanticProjectorPulsePort, -{ - pub(crate) fn new(port: P) -> Self { - Self { - port, - active: AtomicBool::new(false), - } - } - - pub(crate) fn pulse( - &self, - input: &MemorySemanticProjectionInput, - ) -> MemorySemanticProjectorPulseOutcome { - if self - .active - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) - .is_err() - { - return outcome(MemorySemanticProjectorPulseStatus::Busy, vec![], None, None); - } - let _guard = PulseGuard(&self.active); - let scope_id = scope_key(input); - let classification = match self.port.classify(input) { - Ok(classification) => classification, - Err(error) => { - return outcome( - MemorySemanticProjectorPulseStatus::Refused, - vec![MemorySemanticProjectorPulseInspection { - scope_id, - classification: None, - error: Some(format!("{error:#}")), - }], - None, - Some(format!("{error:#}")), - ); - } - }; - let inspections = vec![MemorySemanticProjectorPulseInspection { - scope_id: scope_id.clone(), - classification: Some(classification.clone()), - error: None, - }]; - if let MemorySemanticProjectorPulseClassification::RunningOwned { claim_id } = - classification - { - if let Err(error) = self.port.execute(input, &claim_id) { - return outcome( - MemorySemanticProjectorPulseStatus::Refused, - inspections, - Some(scope_id), - Some(format!("{error:#}")), - ); - } - return outcome( - MemorySemanticProjectorPulseStatus::Executed, - inspections, - Some(scope_id), - None, - ); - } - let Some(purpose) = classification.automatic_purpose() else { - return outcome( - MemorySemanticProjectorPulseStatus::Idle, - inspections, - None, - None, - ); - }; - let claim_id = match self.port.acquire(input, purpose) { - Ok(Some(claim_id)) => claim_id, - Ok(None) => { - return outcome( - MemorySemanticProjectorPulseStatus::Contended, - inspections, - Some(scope_id), - None, - ); - } - Err(error) => { - return outcome( - MemorySemanticProjectorPulseStatus::Refused, - inspections, - Some(scope_id), - Some(format!("{error:#}")), - ); - } - }; - if let Err(error) = self.port.execute(input, &claim_id) { - return outcome( - MemorySemanticProjectorPulseStatus::Refused, - inspections, - Some(scope_id), - Some(format!("{error:#}")), - ); - } - outcome( - MemorySemanticProjectorPulseStatus::Executed, - inspections, - Some(scope_id), - None, - ) - } -} - -struct PulseGuard<'a>(&'a AtomicBool); - -impl Drop for PulseGuard<'_> { - fn drop(&mut self) { - self.0.store(false, Ordering::Release); - } -} - -fn scope_key(input: &MemorySemanticProjectionInput) -> String { - format!( - "{}:{}", - input.obligation().swarm_id, - input.obligation().partition - ) -} - -fn outcome( - status: MemorySemanticProjectorPulseStatus, - inspections: Vec, - selected_scope_id: Option, - error: Option, -) -> MemorySemanticProjectorPulseOutcome { - MemorySemanticProjectorPulseOutcome { - status, - selected_scope_id, - inspections, - error, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::memory_graph::semantic_projector::MemorySemanticProjectionAuthoritySnapshot; - use crate::memory_graph::semantic_projector::{ - classify_memory_semantic_projection_for_pulse, semantic_projector_cache, - }; - use crate::{ - MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION, MemorySemanticProjectionObligation, - MemorySemanticProjectionSourceHead, SEMANTIC_PROJECTION_SCHEMA_VERSION, - }; - use cultcache_rs::CultCache; - use std::sync::{Arc, Barrier, Mutex}; - use tempfile::tempdir; - - fn input(partition: &str) -> MemorySemanticProjectionInput { - let obligation = MemorySemanticProjectionObligation { - schema_version: MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION.to_string(), - obligation_id: format!("obligation-{partition}"), - swarm_id: "swarm-a".to_string(), - partition: partition.to_string(), - canonical_source_id: format!("source-{partition}"), - source_commit_id: "commit-1".to_string(), - graph_id: format!("graph-{partition}"), - source_generation: 1, - source_model_hash: "model-hash".to_string(), - canonical_content_set_hash: "content-hash".to_string(), - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.to_string(), - created_at: "2026-07-15T10:00:00Z".to_string(), - }; - MemorySemanticProjectionInput { - snapshot: crate::EpiphanyMemoryGraphSnapshot { - schema_version: Some("v0".to_string()), - graph_id: obligation.graph_id.clone(), - model_revision: 1, - ..Default::default() - }, - authority: MemorySemanticProjectionAuthoritySnapshot { - head: MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: 1, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }, - envelopes: vec![], - }, - obligation, - } - } - - struct MockPort { - classifications: Mutex< - Vec>, - >, - acquire_result: Mutex>>, - acquisitions: Mutex>, - executions: Mutex>, - execute_barriers: Option<(Arc, Arc)>, - } - - impl MockPort { - fn new(classifications: Vec) -> Self { - Self { - classifications: Mutex::new(classifications.into_iter().map(Ok).collect()), - acquire_result: Mutex::new(Some(Some("claim-1".to_string()))), - acquisitions: Mutex::new(vec![]), - executions: Mutex::new(vec![]), - execute_barriers: None, - } - } - } - - impl MemorySemanticProjectorPulsePort for MockPort { - fn classify( - &self, - _input: &MemorySemanticProjectionInput, - ) -> Result { - self.classifications - .lock() - .unwrap() - .remove(0) - .map_err(anyhow::Error::msg) - } - - fn acquire( - &self, - input: &MemorySemanticProjectionInput, - purpose: &str, - ) -> Result> { - self.acquisitions - .lock() - .unwrap() - .push((scope_key(input), purpose.to_string())); - Ok(self.acquire_result.lock().unwrap().take().unwrap_or(None)) - } - - fn execute(&self, _input: &MemorySemanticProjectionInput, claim_id: &str) -> Result<()> { - self.executions.lock().unwrap().push(claim_id.to_string()); - if let Some((entered, release)) = &self.execute_barriers { - entered.wait(); - release.wait(); - } - Ok(()) - } - } - - #[test] - fn decision_table_never_runs_ready_running_or_stale() { - for classification in [ - MemorySemanticProjectorPulseClassification::Ready, - MemorySemanticProjectorPulseClassification::Running, - MemorySemanticProjectorPulseClassification::Stale, - ] { - let pulser = MemorySemanticProjectorPulser::new(MockPort::new(vec![classification])); - let outcome = pulser.pulse(&input("modeling")); - assert_eq!(outcome.status, MemorySemanticProjectorPulseStatus::Idle); - assert!(pulser.port.acquisitions.lock().unwrap().is_empty()); - assert!(pulser.port.executions.lock().unwrap().is_empty()); - } - } - - #[test] - fn repair_classification_acquires_the_typed_repair_path() { - let pulser = MemorySemanticProjectorPulser::new(MockPort::new(vec![ - MemorySemanticProjectorPulseClassification::Repair, - ])); - let outcome = pulser.pulse(&input("modeling")); - assert_eq!(outcome.status, MemorySemanticProjectorPulseStatus::Executed); - assert_eq!( - pulser.port.acquisitions.lock().unwrap().as_slice(), - &[("swarm-a:modeling".to_string(), "repair".to_string())] - ); - } - - #[test] - fn native_classification_refuses_an_advanced_sealed_input_as_stale() -> Result<()> { - let temp = tempdir()?; - let store = temp.path().join("classification.msgpack"); - let current = input("modeling"); - let mut cache: CultCache = semantic_projector_cache(&store)?; - cache.put(¤t.obligation().obligation_id, current.obligation())?; - assert_eq!( - classify_memory_semantic_projection_for_pulse(&store, ¤t)?, - MemorySemanticProjectorPulseClassification::Pending - ); - let mut stale = current.clone(); - stale.obligation.source_generation += 1; - assert_eq!( - classify_memory_semantic_projection_for_pulse(&store, &stale)?, - MemorySemanticProjectorPulseClassification::Stale - ); - Ok(()) - } - - #[test] - fn pending_and_failed_execute_one_action() { - for classification in [ - MemorySemanticProjectorPulseClassification::Pending, - MemorySemanticProjectorPulseClassification::Failed, - ] { - let pulser = MemorySemanticProjectorPulser::new(MockPort::new(vec![classification])); - let outcome = pulser.pulse(&input("modeling")); - assert_eq!(outcome.status, MemorySemanticProjectorPulseStatus::Executed); - assert_eq!(pulser.port.acquisitions.lock().unwrap().len(), 1); - assert_eq!(pulser.port.executions.lock().unwrap().len(), 1); - } - } - - #[test] - fn contention_consumes_the_one_action_slot_without_false_execution() { - let port = MockPort::new(vec![MemorySemanticProjectorPulseClassification::Pending]); - *port.acquire_result.lock().unwrap() = Some(None); - let pulser = MemorySemanticProjectorPulser::new(port); - let outcome = pulser.pulse(&input("modeling")); - assert_eq!( - outcome.status, - MemorySemanticProjectorPulseStatus::Contended - ); - assert_eq!(outcome.inspections.len(), 1); - assert!(pulser.port.executions.lock().unwrap().is_empty()); - } - - #[test] - fn owned_running_claim_resumes_without_a_second_acquisition() { - let pulser = MemorySemanticProjectorPulser::new(MockPort::new(vec![ - MemorySemanticProjectorPulseClassification::RunningOwned { - claim_id: "recovered-claim".to_string(), - }, - ])); - let outcome = pulser.pulse(&input("modeling")); - assert_eq!(outcome.status, MemorySemanticProjectorPulseStatus::Executed); - assert!(pulser.port.acquisitions.lock().unwrap().is_empty()); - assert_eq!( - pulser.port.executions.lock().unwrap().as_slice(), - ["recovered-claim"] - ); - } - - #[test] - fn overlapping_pulse_is_busy_and_cannot_execute() { - let entered = Arc::new(Barrier::new(2)); - let release = Arc::new(Barrier::new(2)); - let mut port = MockPort::new(vec![MemorySemanticProjectorPulseClassification::Pending]); - port.execute_barriers = Some((entered.clone(), release.clone())); - let pulser = Arc::new(MemorySemanticProjectorPulser::new(port)); - let worker = { - let pulser = pulser.clone(); - std::thread::spawn(move || pulser.pulse(&input("modeling"))) - }; - entered.wait(); - let busy = pulser.pulse(&input("modeling")); - assert_eq!(busy.status, MemorySemanticProjectorPulseStatus::Busy); - release.wait(); - assert_eq!( - worker.join().unwrap().status, - MemorySemanticProjectorPulseStatus::Executed - ); - assert_eq!(pulser.port.executions.lock().unwrap().len(), 1); - } -} diff --git a/epiphany-core/src/mind_documents.rs b/epiphany-core/src/mind_documents.rs index ec6d291c..a4c878bd 100644 --- a/epiphany-core/src/mind_documents.rs +++ b/epiphany-core/src/mind_documents.rs @@ -203,10 +203,8 @@ pub struct EpiphanyMindPersonaPassInputDocument { #[cultcache(key = 3)] pub allowed_channel_ids: Vec, #[cultcache(key = 4)] - pub dynamic_semantic_memory_recall: String, - #[cultcache(key = 5)] pub observed_sources: Vec, - #[cultcache(key = 6)] + #[cultcache(key = 5)] pub admitted_at: String, } diff --git a/epiphany-core/src/persona_conversation.rs b/epiphany-core/src/persona_conversation.rs index 35c12ac2..dc317ace 100644 --- a/epiphany-core/src/persona_conversation.rs +++ b/epiphany-core/src/persona_conversation.rs @@ -1422,7 +1422,6 @@ mod tests { status: "terminal".into(), reserved_at: reserved_at.into(), mentions: vec![], - semantic_memory_recall: serde_json::Value::Null, terminal_receipt: Some(terminal.clone()), private_state_exposed: false, }, @@ -1730,7 +1729,6 @@ mod tests { }, transcript: Vec::new(), allowed_channel_ids: vec!["aquarium".into()], - dynamic_semantic_memory_recall: String::new(), observed_sources: vec![provenance.clone()], admitted_at: "2026-08-18T02:00:01Z".into(), }; @@ -1780,7 +1778,6 @@ mod tests { status: "terminal".into(), reserved_at: "2026-08-09T23:59:59Z".into(), mentions: vec![], - semantic_memory_recall: serde_json::Value::Null, terminal_receipt: Some(crate::PersonaTurnTerminalReceipt { schema_version: crate::PERSONA_TURN_TERMINAL_RECEIPT_SCHEMA_VERSION.into(), receipt_id: "turn-failed:terminal".into(), diff --git a/epiphany-core/src/persona_social_state.rs b/epiphany-core/src/persona_social_state.rs index b62e58a1..a2d955a4 100644 --- a/epiphany-core/src/persona_social_state.rs +++ b/epiphany-core/src/persona_social_state.rs @@ -4,7 +4,6 @@ use cultcache_rs::{ SingleFileMessagePackBackingStore, }; use serde::{Deserialize, Serialize}; -use serde_json::Value; use sha2::Digest; use std::collections::{BTreeMap, HashSet}; use std::path::Path; @@ -57,8 +56,6 @@ pub struct PersonaTurnRequest { pub reserved_at: String, pub mentions: Vec, #[serde(default)] - pub semantic_memory_recall: Value, - #[serde(default)] pub terminal_receipt: Option, pub private_state_exposed: bool, } @@ -434,7 +431,6 @@ pub fn pulse_persona_social( .iter() .map(|document| document.mention.clone()) .collect(), - semantic_memory_recall: serde_json::Value::Null, terminal_receipt: None, private_state_exposed: false, }; @@ -715,7 +711,6 @@ pub fn persona_turn_requests(store_path: impl AsRef) -> Result, #[serde(default)] - pub semantic_memory_recall: String, - #[serde(default)] pub pending_mentions: Vec, #[serde(default)] pub repo_activity: Vec, @@ -261,10 +257,6 @@ pub struct PersonaInterpreterInput { pub persona_prompt: String, pub persona_output: String, #[serde(default)] - pub semantic_memory_recall: String, - #[serde(default)] - pub dynamic_semantic_memory_recall: String, - #[serde(default)] pub pending_mentions: Vec, #[serde(default)] pub allowed_channel_ids: Vec, @@ -280,11 +272,10 @@ pub fn build_persona_projector_prompt_with_transcript( ) -> String { let memory = render_memory_packet(&input.memories); let typed_context = format!( - "prompt schema: {schema}\nPersona identity:\n{identity}\n\nTyped memory packet:\n{memory}\n\nSemantic memory recall:\n{semantic_recall}\n\nPending addressed pressure:\n{mentions}\n\nRecent home-repo activity:\n{activity}\n\nLive social affordances:\n{affordances}", + "prompt schema: {schema}\nPersona identity:\n{identity}\n\nTyped memory packet:\n{memory}\n\nPending addressed pressure:\n{mentions}\n\nRecent home-repo activity:\n{activity}\n\nLive social affordances:\n{affordances}", schema = PERSONA_PROJECTOR_PROMPT_SCHEMA_VERSION, identity = render_identity(&input.identity), memory = memory, - semantic_recall = render_semantic_memory_recall_text(&input.semantic_memory_recall), mentions = render_pending_mentions(&input.pending_mentions), activity = render_repo_activity(&input.repo_activity), affordances = render_social_affordances(&input.social_affordances), @@ -336,24 +327,10 @@ Allowed channel ids: Pending addressed pressure: {mentions} -Initial semantic memory recall from the Persona turn: -{semantic_recall} - -Dynamic self-memory recall from the Persona output: -{dynamic_semantic_recall} "#, schema = PERSONA_INTERPRETER_PROMPT_SCHEMA_VERSION, channels = render_allowed_channels(&input.allowed_channel_ids), mentions = render_pending_mentions(&input.pending_mentions), - semantic_recall = render_semantic_memory_recall_text(&input.semantic_memory_recall), - dynamic_semantic_recall = render_semantic_memory_recall_text( - input - .dynamic_semantic_memory_recall - .trim() - .is_empty() - .then_some(input.semantic_memory_recall.as_str()) - .unwrap_or(input.dynamic_semantic_memory_recall.as_str()) - ), ); let typed_context = format!( "Allowed channel ids:\n{}\n\nPending addressed-pressure records:\n{}", @@ -481,75 +458,6 @@ pub fn parse_and_validate_persona_interpreter_effect_set( Ok(parsed) } -pub fn render_persona_semantic_memory_recall(packet: &EpiphanyMemoryContextPacket) -> String { - let mut lines = vec![ - format!( - "Derived semantic recall packet `{}` from query `{}`.", - packet.id, packet.query_id - ), - "These hits come from Epiphany's typed memory graph. They are hints, not durable authority; reviewed memory/state remains the owner.".to_string(), - ]; - - if packet.summaries.is_empty() && packet.nodes.is_empty() { - lines.push("- no matching memory graph entries in this packet".to_string()); - } - - for (index, summary) in packet.summaries.iter().take(4).enumerate() { - lines.push(format!( - "- summary {}. {}: {}; next: {}", - index + 1, - fallback(&summary.target, "unknown target"), - compact_semantic_recall_line(&summary.claim, 420), - compact_semantic_recall_line(&summary.action_implication, 260) - )); - } - - for (index, node) in packet.nodes.iter().take(8).enumerate() { - lines.push(format!( - "- hit {}. {}: {}; next: {}", - index + 1, - fallback(&node.title, "untitled memory"), - compact_semantic_recall_line(&node.claim, 420), - compact_semantic_recall_line(&node.action_implication, 260) - )); - } - - if !packet.warnings.is_empty() { - lines.push("Warnings:".to_string()); - for warning in packet.warnings.iter().take(4) { - lines.push(format!("- {}", compact_semantic_recall_line(warning, 260))); - } - } - - lines.join("\n") -} - -pub fn semantic_memory_recall_from_heartbeat_action(action: &Value) -> String { - let Some(recall) = action - .get("persona_memory_recall") - .or_else(|| action.get("personaMemoryRecall")) - else { - return "- semantic memory recall unavailable in heartbeat action; do not pretend it ran" - .to_string(); - }; - - if recall.get("privateStateExposed").and_then(Value::as_bool) != Some(false) { - return "- semantic memory recall refused: heartbeat action did not carry a private-state seal" - .to_string(); - } - - recall - .get("renderedRecall") - .and_then(Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .map(ToString::to_string) - .unwrap_or_else(|| { - "- semantic memory recall unavailable in heartbeat action; do not pretend it ran" - .to_string() - }) -} - pub fn persona_projected_surface_is_clean(surface: &str) -> bool { if !ghostlight_persona_projection::narrative_stream_is_clean(surface) { return false; @@ -673,24 +581,6 @@ fn render_allowed_channels(channel_ids: &[String]) -> String { .join("\n") } -fn render_semantic_memory_recall_text(value: &str) -> String { - if value.trim().is_empty() { - return "- semantic memory recall unavailable in this packet; do not pretend it ran" - .to_string(); - } - value.trim().to_string() -} - -fn compact_semantic_recall_line(value: &str, max_len: usize) -> String { - let mut compacted = value.split_whitespace().collect::>().join(" "); - if compacted.len() > max_len { - let keep = max_len.saturating_sub(3); - compacted.truncate(keep); - compacted.push_str("..."); - } - compacted -} - fn fallback<'a>(value: &'a str, fallback: &'a str) -> &'a str { if value.trim().is_empty() { fallback @@ -702,11 +592,6 @@ fn fallback<'a>(value: &'a str, fallback: &'a str) -> &'a str { #[cfg(test)] mod tests { use super::*; - use epiphany_state_model::EpiphanyMemoryContextPacket; - use epiphany_state_model::EpiphanyMemoryFreshnessStatus; - use epiphany_state_model::EpiphanyMemoryNode; - use epiphany_state_model::EpiphanyMemorySummary; - use serde_json::json; fn identity() -> PersonaIdentity { PersonaIdentity { @@ -786,8 +671,6 @@ mod tests { identity: identity(), persona_prompt: persona, persona_output: "I want to answer, but only if I can name the cut plainly.".to_string(), - semantic_memory_recall: String::new(), - dynamic_semantic_memory_recall: String::new(), pending_mentions: vec![pending], allowed_channel_ids: vec!["aquarium".to_string()], }); @@ -798,93 +681,6 @@ mod tests { assert!(interpreter.contains("a signed Bifrost receipt alone proves")); } - #[test] - fn persona_turn_prompts_include_semantic_memory_recall_as_hint_not_authority() { - let recall = render_persona_semantic_memory_recall(&EpiphanyMemoryContextPacket { - id: "memctx-persona-current-room".to_string(), - query_id: "persona-current-room".to_string(), - summaries: vec![EpiphanyMemorySummary { - id: "summary-role-persona".to_string(), - target: "role:Persona".to_string(), - claim: "Persona remembers that public speech should preserve dignity and clean contracts." - .to_string(), - action_implication: "Let this pressure shape tone, but route effects through Mind." - .to_string(), - freshness: EpiphanyMemoryFreshnessStatus::Ready, - confidence: 82, - ..Default::default() - }], - nodes: vec![EpiphanyMemoryNode { - id: "node-persona-value-contracts".to_string(), - title: "Persona value: clean contracts".to_string(), - claim: "Clean typed contracts matter more than fast improvised glue.".to_string(), - action_implication: - "Use as Persona-local context, not as authorization to mutate state." - .to_string(), - ..Default::default() - }], - ..Default::default() - }); - - let projector = build_persona_projector_prompt(&PersonaProjectorInput { - identity: identity(), - semantic_memory_recall: recall.clone(), - ..PersonaProjectorInput::default() - }); - assert!(projector.contains("Semantic memory recall")); - assert!(projector.contains("typed memory graph")); - assert!(projector.contains("not durable authority")); - - let persona = build_persona_turn_prompt(&PersonaTurnInput { - identity: identity(), - projected_state: "Epiphany feels the pressure of the public room.".to_string(), - }); - assert!(persona.contains("Epiphany feels the pressure of the public room")); - assert!(!persona.contains("Semantic memory recall")); - assert!(!persona.contains("Clean typed contracts")); - - let interpreter = build_persona_interpreter_prompt(&PersonaInterpreterInput { - identity: identity(), - persona_prompt: persona, - persona_output: "I can answer, but the answer should stay review-gated.".to_string(), - semantic_memory_recall: recall, - dynamic_semantic_memory_recall: "Output-triggered recall says review gates matter." - .to_string(), - pending_mentions: Vec::new(), - allowed_channel_ids: vec!["aquarium".to_string()], - }); - assert!(interpreter.contains("Dynamic self-memory recall")); - assert!(interpreter.contains("Output-triggered recall")); - assert!(interpreter.contains("STATE NOTE")); - assert!(interpreter.contains("SAY")); - } - - #[test] - fn heartbeat_action_recall_extracts_only_when_private_state_is_sealed() { - let action = json!({ - "persona_memory_recall": { - "privateStateExposed": false, - "renderedRecall": "Derived Qdrant Persona recall; hints only." - } - }); - assert_eq!( - semantic_memory_recall_from_heartbeat_action(&action), - "Derived Qdrant Persona recall; hints only." - ); - - let leaking_action = json!({ - "persona_memory_recall": { - "privateStateExposed": true, - "renderedRecall": "sealed private note" - } - }); - let refused = semantic_memory_recall_from_heartbeat_action(&leaking_action); - assert!(refused.contains("refused")); - assert!(!refused.contains("sealed private note")); - - let missing = semantic_memory_recall_from_heartbeat_action(&json!({})); - assert!(missing.contains("unavailable")); - } #[test] fn projected_surface_rejects_side_effect_syntax() { diff --git a/epiphany-core/src/repo_model_documents.rs b/epiphany-core/src/repo_model_documents.rs index 2d196694..5997b37a 100644 --- a/epiphany-core/src/repo_model_documents.rs +++ b/epiphany-core/src/repo_model_documents.rs @@ -146,39 +146,17 @@ impl EpiphanyRepoModelView { pub fn memory_context_projection(&self) -> EpiphanyMemoryGraphSnapshot { EpiphanyMemoryGraphSnapshot { - schema_version: None, graph_id: self.identity.graph_id.clone(), - model_revision: 0, - model_hash: String::new(), - source: None, domains: self.domains.clone(), nodes: self.nodes.clone(), edges: self.edges.clone(), summaries: self.summaries.clone(), - embedding_manifest: None, - freshness: None, lifecycle_receipts: self.lifecycle_receipts.clone(), frontier: self.frontier.clone(), } } } -pub(crate) fn derive_repo_model_semantic_projection_obligation( - view: &EpiphanyRepoModelView, - created_at: &str, -) -> Result { - let mut projection = view.memory_context_projection(); - projection.model_revision = 1; - projection.model_hash = crate::memory_graph_model_hash(&projection)?; - crate::derive_memory_semantic_projection_obligation( - &projection, - &view.identity.swarm_id, - &format!("epiphany.runtime/{}/repo-model", view.identity.runtime_id), - &view.projection_digest, - created_at, - ) -} - impl EpiphanyRepoModelBasis { pub fn validate(&self) -> Result<()> { let digest = self @@ -579,7 +557,6 @@ pub fn initialize_keyed_repo_model( if !repo_model_view_matches_seed(&view, seed)? { return Err(anyhow!("RepoModel seed replay found divergent keyed state")); } - crate::runtime_modeling_semantic_projection_input(store_path)?; return Ok(view); } @@ -647,10 +624,7 @@ pub fn initialize_keyed_repo_model( writes, seeded_at, )? { - crate::EpiphanyMindCommitOutcome::Committed(_) => { - crate::runtime_modeling_semantic_projection_input(store_path)?; - assemble_repo_model_view(store_path) - } + crate::EpiphanyMindCommitOutcome::Committed(_) => assemble_repo_model_view(store_path), crate::EpiphanyMindCommitOutcome::Conflict { .. } => { Err(anyhow!("RepoModel seed lost its exact-envelope commit")) } @@ -1934,14 +1908,6 @@ mod tests { .iter() .any(|receipt| receipt.invariant_owner == "Modeling.repo_model_seed") ); - assert_eq!( - cache - .get_all::()? - .into_iter() - .filter(|obligation| obligation.partition == "modeling") - .count(), - 1 - ); assert!( cache .snapshot_envelopes() @@ -2361,35 +2327,6 @@ mod tests { .collect::>(), ["node-left", "node-right"] ); - let semantic = crate::runtime_modeling_semantic_projection_input(&store)?; - assert_eq!( - semantic.source_head().source_commit_id, - reopened.projection_digest - ); - assert_eq!( - semantic.obligation().source_commit_id, - reopened.projection_digest - ); - assert!( - semantic - .authority - .envelopes - .iter() - .any(|envelope| { envelope.r#type == crate::EpiphanyMindCommitReceipt::TYPE }) - ); - let mut reopened_cache = runtime_spine_cache(&store)?; - reopened_cache.pull_all_backing_stores()?; - assert_eq!( - reopened_cache - .get_all::()? - .into_iter() - .filter(|obligation| obligation.partition == "modeling") - .count(), - 2 - ); - let replayed_semantic = crate::runtime_modeling_semantic_projection_input(&store)?; - assert_eq!(replayed_semantic.obligation(), semantic.obligation()); - let competing = [ make_proposal( "proposal-collision-left", diff --git a/epiphany-core/src/repository_body_observer.rs b/epiphany-core/src/repository_body_observer.rs index 02bdbebc..40535483 100644 --- a/epiphany-core/src/repository_body_observer.rs +++ b/epiphany-core/src/repository_body_observer.rs @@ -214,97 +214,6 @@ pub struct RepositoryBodyManifest { pub entries: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] -#[allow(dead_code)] // Sealed input for the not-yet-wired coverage projector. -pub(crate) struct VerifiedRepositoryBodyBytes { - pub relative_path: String, - pub raw_sha256: String, - pub bytes: Vec, -} - -/// One authenticated view of a persisted Repository Body generation. -/// -/// Opening the session authenticates the runtime route and the complete -/// binding/head/observation/manifest chain once. Reads reuse that sealed view; -/// they never reload the whole CultCache store for each file. -pub(crate) struct RepositoryBodyReadSession { - basis: RepositoryBodyObservationBasis, - manifest: RepositoryBodyManifest, - root: PathBuf, - body_store: PathBuf, -} - -impl RepositoryBodyReadSession { - pub(crate) fn open( - runtime_store: &Path, - basis: &RepositoryBodyObservationBasis, - ) -> Result { - let route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - let entries = load_body_envelopes(Path::new(&route.body_store_path))?; - let binding: RepositoryBodyBinding = decode( - find(&entries, BODY_BINDING_TYPE, BODY_BINDING_KEY) - .ok_or_else(|| anyhow!("runtime repository Body store has no Body binding"))?, - )?; - let head: RepositoryBodyHead = decode( - find(&entries, BODY_HEAD_TYPE, BODY_HEAD_KEY) - .ok_or_else(|| anyhow!("runtime repository Body store has no current Body head"))?, - )?; - let (observation, manifest) = validate_body_chain(&entries, &binding, &head)?; - if basis.schema_version != BODY_SCHEMA_VERSION - || binding.runtime_id != route.runtime_id - || binding.swarm_id != route.swarm_id - || binding.workspace_id != route.workspace_id - || body_binding_sha256(&binding)? != route.body_binding_sha256 - || basis.runtime_id != binding.runtime_id - || basis.swarm_id != binding.swarm_id - || basis.workspace_id != binding.workspace_id - || basis.scope != binding.scope - || basis.body_binding_sha256 != route.body_binding_sha256 - || head.workspace_id != basis.workspace_id - || head.observation_id != basis.observation_id - || head.generation != basis.generation - || head.manifest_root_sha256 != basis.manifest_root_sha256 - || observation.observation_id != basis.observation_id - || observation.generation != basis.generation - || observation.manifest_root_sha256 != basis.manifest_root_sha256 - || observation.scan_started_at != basis.scan_started_at - || observation.scan_finished_at != basis.scan_finished_at - { - bail!("repository Body read session disagrees with its authenticated route or basis"); - } - let root = std::fs::canonicalize(&binding.git_top_level) - .context("bound repository root is missing")?; - if root != PathBuf::from(&binding.git_top_level) { - bail!("bound repository root is no longer canonical"); - } - Ok(Self { - basis: basis.clone(), - manifest, - root, - body_store: PathBuf::from(route.body_store_path), - }) - } - - pub(crate) fn basis(&self) -> &RepositoryBodyObservationBasis { - &self.basis - } - - pub(crate) fn manifest(&self) -> &RepositoryBodyManifest { - &self.manifest - } - - pub(crate) fn body_store(&self) -> &Path { - &self.body_store - } - - pub(crate) fn read_regular_file( - &self, - relative_path: &str, - ) -> Result { - read_verified_repository_body_bytes_from_session(self, relative_path) - } -} #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] #[cultcache(type = "epiphany.repository_body.head", schema = "RepositoryBodyHead")] @@ -601,115 +510,6 @@ pub fn authenticated_repository_body_manifest( let (_, manifest) = validate_body_chain(&entries, &binding, &historical_head)?; Ok(manifest) } - -#[allow(dead_code)] // Sealed input for the not-yet-wired coverage projector. -pub(crate) fn read_verified_repository_body_bytes( - runtime_store: &Path, - basis: &RepositoryBodyObservationBasis, - relative_path: &str, -) -> Result { - RepositoryBodyReadSession::open(runtime_store, basis)?.read_regular_file(relative_path) -} - -fn read_verified_repository_body_bytes_from_session( - session: &RepositoryBodyReadSession, - relative_path: &str, -) -> Result { - validate_portable_relative_path(relative_path)?; - let entry = session - .manifest - .entries - .iter() - .find(|entry| entry.path == relative_path) - .ok_or_else(|| { - anyhow!("path {relative_path:?} is not included in the historical Body manifest") - })?; - if entry.kind != "regular" - || (entry.git_mode != "100644" && entry.git_mode != "100755") - || entry.gitlink_oid.is_some() - || entry.raw_sha256.len() != 64 - || !entry - .raw_sha256 - .bytes() - .all(|byte| byte.is_ascii_hexdigit()) - { - bail!("historical Body entry {relative_path:?} is not an authenticated regular file"); - } - - let root = &session.root; - let path = safe_worktree_path(root, relative_path)?; - reject_reparse_or_symlink_components(&root, relative_path)?; - let resolved = std::fs::canonicalize(&path) - .with_context(|| format!("historical Body path {relative_path:?} is missing"))?; - if !resolved.starts_with(&root) || resolved != path { - bail!( - "historical Body path {relative_path:?} does not resolve canonically beneath its bound root" - ); - } - - let before = std::fs::symlink_metadata(&path)?; - if !before.file_type().is_file() || metadata_is_reparse_point(&before) { - bail!("historical Body path {relative_path:?} is no longer a regular file"); - } - #[cfg(test)] - BODY_FILE_READS.set(BODY_FILE_READS.get() + 1); - let bytes = std::fs::read(&path) - .with_context(|| format!("cannot read historical Body path {relative_path:?}"))?; - let after = std::fs::symlink_metadata(&path)?; - require_stable_metadata(relative_path, &before, &after)?; - if metadata_is_reparse_point(&after) || !after.file_type().is_file() { - bail!("historical Body path {relative_path:?} changed kind during raw read"); - } - let actual_sha256 = format!("{:x}", Sha256::digest(&bytes)); - if bytes.len() as u64 != entry.raw_byte_length || actual_sha256 != entry.raw_sha256 { - bail!( - "historical Body path {relative_path:?} bytes disagree with its authenticated manifest entry" - ); - } - Ok(VerifiedRepositoryBodyBytes { - relative_path: relative_path.into(), - raw_sha256: actual_sha256, - bytes, - }) -} - -fn validate_portable_relative_path(path: &str) -> Result<()> { - if path.is_empty() || path.starts_with('/') || path.contains('\\') { - bail!("unsafe or non-portable Body path {path:?}"); - } - if path - .split('/') - .any(|part| part.is_empty() || part == "." || part == "..") - { - bail!("unsafe or non-portable Body path {path:?}"); - } - Ok(()) -} - -fn reject_reparse_or_symlink_components(root: &Path, relative: &str) -> Result<()> { - let mut cursor = root.to_path_buf(); - for component in relative.split('/') { - cursor.push(component); - let metadata = std::fs::symlink_metadata(&cursor) - .with_context(|| format!("historical Body path {relative:?} is missing"))?; - if metadata.file_type().is_symlink() || metadata_is_reparse_point(&metadata) { - bail!("historical Body path {relative:?} traverses a symlink or reparse point"); - } - } - Ok(()) -} - -#[cfg(windows)] -fn metadata_is_reparse_point(metadata: &std::fs::Metadata) -> bool { - use std::os::windows::fs::MetadataExt; - metadata.file_attributes() & 0x400 != 0 -} - -#[cfg(not(windows))] -fn metadata_is_reparse_point(_: &std::fs::Metadata) -> bool { - false -} - pub fn observe_repository_body( repo: &Path, store: &Path, @@ -1949,132 +1749,6 @@ mod tests { Ok(()) } #[test] - fn coverage_obligation_refuses_manifest_entries_substituted_under_declared_root() -> Result<()> - { - let d = repo()?; - let state = tempfile::tempdir()?; - let (store, runtime) = bound( - d.path(), - state.path(), - "coverage-workspace", - "runtime", - "swarm", - )?; - write(&d.path().join("source.rs"), "fn original() {}")?; - run(d.path(), &["add", "."])?; - let basis = observe_runtime_repository_body_basis(&runtime)?; - let opening = SingleFileMessagePackBackingStore::new(&store).pull_all()?; - let original = find(&opening, BODY_MANIFEST_TYPE, &basis.manifest_root_sha256) - .ok_or_else(|| anyhow!("test Body manifest missing"))?; - let mut substituted: RepositoryBodyManifest = decode(original)?; - substituted.entries[0].raw_sha256 = "attacker-chosen-content-hash".into(); - let replacement = envelope( - BODY_MANIFEST_TYPE, - &basis.manifest_root_sha256, - &substituted, - )?; - assert!( - SingleFileMessagePackBackingStore::new(&store) - .compare_and_swap_batch(&[original.clone()], vec![replacement])? - ); - let policy = crate::WorkspaceCoveragePolicy::bounded_regular_files_v0(1024)?; - assert!(crate::derive_workspace_coverage_obligation(&runtime, &basis, &policy).is_err()); - Ok(()) - } - #[test] - fn verified_body_bytes_match_authenticated_historical_entry() -> Result<()> { - let d = repo()?; - let state = tempfile::tempdir()?; - let (_, runtime) = bound(d.path(), state.path(), "verified", "runtime", "swarm")?; - std::fs::write(d.path().join("source.bin"), [0_u8, 255, 7, 9])?; - run(d.path(), &["add", "."])?; - let basis = observe_runtime_repository_body_basis(&runtime)?; - let verified = read_verified_repository_body_bytes(&runtime, &basis, "source.bin")?; - assert_eq!(verified.relative_path, "source.bin"); - assert_eq!(verified.bytes, [0_u8, 255, 7, 9]); - assert_eq!( - verified.raw_sha256, - format!("{:x}", Sha256::digest(&verified.bytes)) - ); - Ok(()) - } - #[test] - fn verified_body_bytes_refuse_changed_or_substituted_current_body() -> Result<()> { - let d = repo()?; - let state = tempfile::tempdir()?; - let (_, runtime) = bound(d.path(), state.path(), "verified", "runtime", "swarm")?; - write(&d.path().join("tracked"), "AAAA")?; - run(d.path(), &["add", "."])?; - let historical = observe_runtime_repository_body_basis(&runtime)?; - - write(&d.path().join("tracked"), "BBBB")?; - assert!( - read_verified_repository_body_bytes(&runtime, &historical, "tracked") - .unwrap_err() - .to_string() - .contains("bytes disagree") - ); - let advanced = observe_runtime_repository_body_basis(&runtime)?; - assert!(advanced.generation > historical.generation); - assert_eq!( - read_verified_repository_body_bytes(&runtime, &advanced, "tracked")?.bytes, - b"BBBB" - ); - - std::fs::remove_file(d.path().join("tracked"))?; - std::fs::create_dir(d.path().join("tracked"))?; - assert!( - read_verified_repository_body_bytes(&runtime, &advanced, "tracked") - .unwrap_err() - .to_string() - .contains("regular file") - ); - Ok(()) - } - #[test] - fn verified_body_bytes_refuse_noncanonical_and_nonmanifest_paths() -> Result<()> { - let d = repo()?; - let state = tempfile::tempdir()?; - let (_, runtime) = bound(d.path(), state.path(), "verified", "runtime", "swarm")?; - write(&d.path().join("tracked"), "body")?; - run(d.path(), &["add", "."])?; - let basis = observe_runtime_repository_body_basis(&runtime)?; - for path in [ - "", - "/tracked", - "../tracked", - "a/../tracked", - "./tracked", - "a\\tracked", - ] { - assert!(read_verified_repository_body_bytes(&runtime, &basis, path).is_err()); - } - assert!(read_verified_repository_body_bytes(&runtime, &basis, "untracked").is_err()); - Ok(()) - } - #[cfg(unix)] - #[test] - fn verified_body_bytes_refuse_symlink_substitution_and_parent_escape() -> Result<()> { - use std::os::unix::fs::symlink; - - let d = repo()?; - let state = tempfile::tempdir()?; - let (_, runtime) = bound(d.path(), state.path(), "verified", "runtime", "swarm")?; - std::fs::create_dir(d.path().join("inside"))?; - write(&d.path().join("inside/tracked"), "body")?; - run(d.path(), &["add", "."])?; - let basis = observe_runtime_repository_body_basis(&runtime)?; - std::fs::remove_file(d.path().join("inside/tracked"))?; - symlink("../.git/HEAD", d.path().join("inside/tracked"))?; - assert!(read_verified_repository_body_bytes(&runtime, &basis, "inside/tracked").is_err()); - - std::fs::remove_file(d.path().join("inside/tracked"))?; - std::fs::remove_dir(d.path().join("inside"))?; - symlink(".git", d.path().join("inside"))?; - assert!(read_verified_repository_body_bytes(&runtime, &basis, "inside/tracked").is_err()); - Ok(()) - } - #[test] fn ignored_and_mtime_only_are_unchanged() -> Result<()> { let d = repo()?; let state = tempfile::tempdir()?; diff --git a/epiphany-core/src/repository_readiness.rs b/epiphany-core/src/repository_readiness.rs deleted file mode 100644 index 120d02e2..00000000 --- a/epiphany-core/src/repository_readiness.rs +++ /dev/null @@ -1,1415 +0,0 @@ -use crate::memory_graph::semantic_index::{ - MemorySemanticIndexConfig, MemorySemanticLiveEvidence, observe_memory_semantic_live_evidence, -}; -use crate::semantic_backend::{QdrantBackend, QdrantConfig}; -use crate::workspace_coverage_projector::{ - WorkspaceCoverageReadinessEvidence, observe_current_workspace_coverage_evidence, -}; -use crate::{ - EpiphanyMindDocumentVersion, EpiphanyRepoModelView, - MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION, - MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION, MemorySemanticIndexReceipt, - MemorySemanticProjectionAttempt, MemorySemanticProjectionClaim, MemorySemanticProjectionInput, - MemorySemanticProjectionObligation, MemorySemanticProjectionReadiness, - MemorySemanticProjectionSourceHead, RepositoryBodyObservationBasis, - SEMANTIC_PROJECTION_SCHEMA_VERSION, WorkspaceCoveragePolicy, assemble_repo_model_view, - load_memory_semantic_projection_readiness, observe_runtime_repository_body_basis, - runtime_modeling_semantic_projection_input, runtime_spine_cache, - validate_memory_semantic_projection_obligation, -}; -use anyhow::{Result, anyhow, bail}; -use cultcache_rs::{ - CacheBackingStore, CultCacheEnvelope, DatabaseEntry, SingleFileMessagePackBackingStore, -}; -use sha2::{Digest, Sha256}; -use std::path::Path; - -pub const REPOSITORY_READINESS_PROJECTION_SCHEMA_VERSION: &str = - "gamecult.epiphany.repository_readiness_projection.v1"; -pub const REPOSITORY_READINESS_PROJECTION_TYPE: &str = - "gamecult.epiphany.repository_readiness_projection"; - -/// A historical proof that Mind joined one exact Repository Body observation, -/// canonical keyed RepoModel basis, and both live semantic projections. It is not -/// a current-readiness flag: callers must derive a new projection to claim now. -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.repository_readiness_projection", - schema = "RepositoryReadinessProjection" -)] -pub struct RepositoryReadinessProjection { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub projection_id: String, - #[cultcache(key = 2)] - pub status: String, - #[cultcache(key = 3)] - pub observed_ready_at: String, - #[cultcache(key = 4)] - pub workspace_id: String, - #[cultcache(key = 5)] - pub body_binding_sha256: String, - #[cultcache(key = 6)] - pub body_manifest_root_sha256: String, - #[cultcache(key = 7)] - pub body_r1_observation_id: String, - #[cultcache(key = 8)] - pub body_r1_generation: u64, - #[cultcache(key = 9)] - pub body_r2_observation_id: String, - #[cultcache(key = 10)] - pub body_r2_generation: u64, - #[cultcache(key = 11)] - pub repo_model_graph_id: String, - #[cultcache(key = 12)] - pub repo_model_projection_digest: String, - #[cultcache(key = 13)] - pub repo_model_source_documents: Vec, - #[cultcache(key = 15)] - pub modeling_obligation_id: String, - #[cultcache(key = 16)] - pub modeling_receipt_id: String, - #[cultcache(key = 17)] - pub modeling_collection_name: String, - #[cultcache(key = 18)] - pub modeling_observed_point_count: u32, - #[cultcache(key = 19)] - pub modeling_observed_vector_binding_root_sha256: String, - #[cultcache(key = 20)] - pub workspace_policy_id: String, - #[cultcache(key = 21)] - pub workspace_policy_sha256: String, - #[cultcache(key = 22)] - pub workspace_coverage_receipt_id: String, - #[cultcache(key = 23)] - pub workspace_coverage_collection_name: String, - #[cultcache(key = 24)] - pub workspace_coverage_observed_point_count: u64, - #[cultcache(key = 25)] - pub workspace_coverage_point_binding_set_sha256: String, - #[cultcache(key = 26)] - pub workspace_coverage_vector_binding_set_sha256: String, - #[cultcache(key = 27)] - pub opening_non_body_authority_sha256: String, - #[cultcache(key = 28)] - pub closing_non_body_authority_sha256: String, - #[cultcache(key = 29)] - pub contract: String, - #[cultcache(key = 30)] - pub swarm_id: String, - #[cultcache(key = 31)] - pub runtime_id: String, - #[cultcache(key = 32)] - pub body_scope: String, - #[cultcache(key = 33)] - pub body_r1: RepositoryBodyObservationBasis, - #[cultcache(key = 34)] - pub body_r2: RepositoryBodyObservationBasis, - #[cultcache(key = 35)] - pub truth_interval_started_at: String, - #[cultcache(key = 36)] - pub truth_interval_closed_at: String, - #[cultcache(key = 38)] - pub modeling_source_generation: u64, - #[cultcache(key = 39)] - pub modeling_canonical_content_set_hash: String, - #[cultcache(key = 40)] - pub modeling_claim_id: String, - #[cultcache(key = 41)] - pub modeling_claim_epoch: u64, - #[cultcache(key = 42)] - pub modeling_embedding_provider_id: String, - #[cultcache(key = 43)] - pub modeling_embedding_model: String, - #[cultcache(key = 44)] - pub modeling_vector_dimensions: u32, - #[cultcache(key = 45)] - pub modeling_receipt_envelope_sha256: String, - #[cultcache(key = 46)] - pub modeling_live_evidence_sha256: String, - #[cultcache(key = 47)] - pub workspace_obligation_envelope_sha256: String, - #[cultcache(key = 48)] - pub workspace_plan_envelope_sha256: String, - #[cultcache(key = 49)] - pub workspace_claim_id: String, - #[cultcache(key = 50)] - pub workspace_claim_epoch: u64, - #[cultcache(key = 51)] - pub workspace_claim_envelope_sha256: String, - #[cultcache(key = 52)] - pub workspace_attempt_id: String, - #[cultcache(key = 53)] - pub workspace_attempt_envelope_sha256: String, - #[cultcache(key = 54)] - pub workspace_receipt_envelope_sha256: String, - #[cultcache(key = 55)] - pub workspace_head_envelope_sha256: String, - #[cultcache(key = 56)] - pub workspace_observed_point_set_sha256: String, - #[cultcache(key = 58)] - pub modeling_obligation_envelope_sha256: String, - #[cultcache(key = 59)] - pub modeling_canonical_source_id: String, - #[cultcache(key = 60)] - pub modeling_source_commit_id: String, - #[cultcache(key = 61)] - pub modeling_semantic_source_hash: String, - #[cultcache(key = 62)] - pub modeling_current_content_set_hash: String, - #[cultcache(key = 63)] - pub modeling_claim_envelope_sha256: String, - #[cultcache(key = 64)] - pub modeling_attempt_id: String, - #[cultcache(key = 65)] - pub modeling_attempt_envelope_sha256: String, - #[cultcache(key = 66)] - pub workspace_embedding_provider_id: String, - #[cultcache(key = 67)] - pub workspace_embedding_model: String, - #[cultcache(key = 68)] - pub workspace_vector_dimensions: u32, - #[cultcache(key = 69)] - pub workspace_obligation_id: String, - #[cultcache(key = 70)] - pub workspace_plan_id: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceProjectionIdentity { - pub policy: WorkspaceCoveragePolicy, - pub qdrant_url: String, - pub qdrant_api_key: Option, - pub qdrant_timeout_ms: u64, - pub embedding_provider_id: String, - pub embedding_model: String, - pub vector_dimensions: u32, -} - -#[derive(Clone)] -struct JoinedReadinessEvidence { - r1: RepositoryBodyObservationBasis, - r2: RepositoryBodyObservationBasis, - repo_model: EpiphanyRepoModelView, - modeling_obligation_id: String, - modeling_receipt_id: String, - modeling_source_generation: u64, - modeling_canonical_content_set_hash: String, - modeling_claim_id: String, - modeling_claim_epoch: u64, - modeling_embedding_provider_id: String, - modeling_embedding_model: String, - modeling_vector_dimensions: u32, - modeling_receipt_envelope_sha256: String, - modeling_obligation_envelope_sha256: String, - modeling_canonical_source_id: String, - modeling_source_commit_id: String, - modeling_semantic_source_hash: String, - modeling_current_content_set_hash: String, - modeling_claim_envelope_sha256: String, - modeling_attempt_id: String, - modeling_attempt_envelope_sha256: String, - workspace_identity: WorkspaceProjectionIdentity, - modeling_live: Option, - coverage_live: Option, - opening_authority: Vec, - closing_authority: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -enum ReadinessAppendResult { - Appended, - ConcurrentIdentical, -} - -/// The I/O boundary around Mind's readiness join. Implementations may observe -/// and authenticate evidence, but they do not decide whether the evidence is a -/// coherent readiness interval; that decision remains in `observe_with_ports`. -trait ReadinessObservationPorts { - fn observe_body(&mut self) -> Result; - fn observe_store_snapshot(&mut self) -> Result>; - fn observe_semantic_state(&mut self) -> Result; - fn observe_semantic_live(&mut self) -> Result>; - fn observe_workspace_live( - &mut self, - r1: &RepositoryBodyObservationBasis, - _opening: &JoinedReadinessEvidence, - ) -> Result>; - fn close_time(&mut self) -> String; - fn append_projection( - &mut self, - snapshot: &[CultCacheEnvelope], - projection: &RepositoryReadinessProjection, - ) -> Result; -} - -#[derive(Clone, Debug, PartialEq)] -struct RepoModelSemanticContent { - graph_id: String, - domains: Vec, - nodes: Vec, - edges: Vec, - summaries: Vec, - lifecycle_receipts: Vec, - frontier: Vec, -} - -impl RepoModelSemanticContent { - fn from_repo_model(model: &EpiphanyRepoModelView) -> Self { - Self { - graph_id: model.identity.graph_id.clone(), - domains: model.domains.clone(), - nodes: model.nodes.clone(), - edges: model.edges.clone(), - summaries: model.summaries.clone(), - lifecycle_receipts: model.lifecycle_receipts.clone(), - frontier: model.frontier.clone(), - } - } - - fn from_semantic_input(input: &MemorySemanticProjectionInput) -> Self { - let snapshot = input.snapshot(); - Self { - graph_id: snapshot.graph_id.clone(), - domains: snapshot.domains.clone(), - nodes: snapshot.nodes.clone(), - edges: snapshot.edges.clone(), - summaries: snapshot.summaries.clone(), - lifecycle_receipts: snapshot.lifecycle_receipts.clone(), - frontier: snapshot.frontier.clone(), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -struct RawSemanticObservation { - repo_model: EpiphanyRepoModelView, - semantic_content: RepoModelSemanticContent, - authority_envelopes: Vec, - obligation: MemorySemanticProjectionObligation, - current: MemorySemanticProjectionSourceHead, - receipt: MemorySemanticIndexReceipt, -} - -fn validate_exact_raw_semantic_chain( - r1: &RepositoryBodyObservationBasis, - model: &EpiphanyRepoModelView, - raw: &RawSemanticObservation, -) -> Result<()> { - let obligation = &raw.obligation; - let current = &raw.current; - let receipt = &raw.receipt; - validate_memory_semantic_projection_obligation(obligation)?; - if obligation.schema_version != MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION - || obligation.projection_schema_version != SEMANTIC_PROJECTION_SCHEMA_VERSION - || obligation.partition != "modeling" - || obligation.swarm_id != r1.swarm_id - || obligation.graph_id != model.identity.graph_id - || obligation.canonical_source_id.trim().is_empty() - || obligation.source_commit_id.trim().is_empty() - || obligation.canonical_content_set_hash.trim().is_empty() - { - bail!("raw Modeling obligation does not match the canonical RepoModel"); - } - let expected_current = MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }; - if *current != expected_current { - bail!("raw Modeling source head does not equal its exact obligation"); - } - if receipt.schema_version != MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION - || receipt.status != "ready" - || receipt.obligation_id != obligation.obligation_id - || receipt.swarm_id != obligation.swarm_id - || receipt.partition != obligation.partition - || receipt.canonical_source_id != obligation.canonical_source_id - || receipt.source_commit_id != obligation.source_commit_id - || receipt.graph_id != obligation.graph_id - || receipt.source_generation != obligation.source_generation - || receipt.model_revision != obligation.source_generation - || receipt.model_hash != obligation.source_model_hash - || receipt.canonical_content_set_hash != obligation.canonical_content_set_hash - || receipt.projection_schema_version != obligation.projection_schema_version - || receipt.collection_name.trim().is_empty() - || receipt.embedding_provider_id.trim().is_empty() - || receipt.embedding_model.trim().is_empty() - || receipt.vector_dimensions == 0 - || receipt.claim_id.trim().is_empty() - || receipt.claim_epoch == 0 - || receipt.observed_vector_binding_root_sha256.len() != 64 - || !receipt - .observed_vector_binding_root_sha256 - .bytes() - .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b)) - || chrono::DateTime::parse_from_rfc3339(&receipt.indexed_at).is_err() - { - bail!("raw Modeling receipt does not match its exact obligation and RepoModel"); - } - if raw.semantic_content != RepoModelSemanticContent::from_repo_model(model) { - bail!("Modeling semantic input is not the canonical keyed RepoModel content"); - } - Ok(()) -} - -fn observe_with_ports( - ports: &mut P, - workspace_identity: &WorkspaceProjectionIdentity, -) -> Result { - let r1 = ports.observe_body()?; - let opening_snapshot = ports.observe_store_snapshot()?; - let opening_semantic = ports.observe_semantic_state()?; - let mut evidence = derive_joined_opening( - &opening_snapshot, - &r1, - &opening_semantic, - workspace_identity, - )?; - let modeling_live = ports.observe_semantic_live()?; - let coverage_live = ports.observe_workspace_live(&r1, &evidence)?; - let r2 = ports.observe_body()?; - if !same_body_content(&r1, &r2) { - bail!("Repository Body changed during readiness observation"); - } - let closing_semantic = ports.observe_semantic_state()?; - let closing_modeling_live = ports.observe_semantic_live()?; - if closing_modeling_live != modeling_live { - bail!("live Modeling semantic evidence changed during readiness observation"); - } - // Coverage is deliberately rebound to R1 on both reads. R2 closes the Body - // interval; it must not silently change the projection being authenticated. - let closing_coverage_live = ports.observe_workspace_live(&r1, &evidence)?; - if closing_coverage_live != coverage_live { - bail!("live workspace coverage evidence changed during readiness observation"); - } - let closing_snapshot = ports.observe_store_snapshot()?; - let closing_evidence = derive_joined_opening( - &closing_snapshot, - &r1, - &closing_semantic, - workspace_identity, - )?; - if opening_semantic != closing_semantic || evidence.repo_model != closing_evidence.repo_model { - bail!("non-Body readiness authority advanced during observation"); - } - evidence.r2 = r2; - evidence.modeling_live = modeling_live; - evidence.coverage_live = coverage_live; - evidence.closing_authority = readiness_authority_from_snapshot(&closing_snapshot); - let observed_ready_at = ports.close_time(); - let projection = projection_from_join(evidence, &observed_ready_at)?; - ports.append_projection(&closing_snapshot, &projection)?; - Ok(projection) -} - -fn same_body_content( - a: &RepositoryBodyObservationBasis, - b: &RepositoryBodyObservationBasis, -) -> bool { - a.workspace_id == b.workspace_id - && a.swarm_id == b.swarm_id - && a.runtime_id == b.runtime_id - && a.scope == b.scope - && a.body_binding_sha256 == b.body_binding_sha256 - && a.manifest_root_sha256 == b.manifest_root_sha256 -} - -fn authority_bytes(rows: &[CultCacheEnvelope]) -> Result> { - let mut rows = rows.to_vec(); - rows.sort_by(|a, b| (&a.r#type, &a.key).cmp(&(&b.r#type, &b.key))); - rmp_serde::to_vec_named(&rows).map_err(Into::into) -} - -fn envelope_sha256(envelope: &CultCacheEnvelope) -> Result { - Ok(format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(envelope)?) - )) -} - -fn projection_from_join( - evidence: JoinedReadinessEvidence, - observed_ready_at: &str, -) -> Result { - let observed_ready = chrono::DateTime::parse_from_rfc3339(observed_ready_at) - .map_err(|_| anyhow!("repository readiness observation timestamp must be RFC3339"))?; - let body_closed = chrono::DateTime::parse_from_rfc3339(&evidence.r2.scan_finished_at) - .map_err(|_| anyhow!("Repository Body R2 close timestamp must be RFC3339"))?; - if observed_ready < body_closed { - bail!("repository readiness close time predates Body R2 observation"); - } - if !same_body_content(&evidence.r1, &evidence.r2) { - bail!("Repository Body changed during readiness observation"); - } - if evidence.repo_model.identity.workspace_id != evidence.r1.workspace_id - || evidence.repo_model.identity.swarm_id != evidence.r1.swarm_id - || evidence.repo_model.identity.runtime_id != evidence.r1.runtime_id - || evidence.repo_model.identity.body_binding_sha256 != evidence.r1.body_binding_sha256 - { - bail!("current keyed RepoModel identity is not authenticated by Body R1"); - } - let modeling = evidence - .modeling_live - .ok_or_else(|| anyhow!("live Modeling semantic evidence is absent"))?; - let coverage = evidence - .coverage_live - .ok_or_else(|| anyhow!("live workspace coverage evidence is absent"))?; - let opening = authority_bytes(&evidence.opening_authority)?; - let closing = authority_bytes(&evidence.closing_authority)?; - if opening != closing { - bail!("non-Body readiness authority advanced during observation"); - } - let authority_sha256 = format!("{:x}", Sha256::digest(&opening)); - let modeling_live_sha256 = format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(&( - &modeling.collection_name, - modeling.observed_point_count, - &modeling.observed_vector_binding_root_sha256, - ))?) - ); - let r1 = evidence.r1.clone(); - let r2 = evidence.r2.clone(); - let identity = rmp_serde::to_vec_named(&( - &evidence.r1.workspace_id, - &evidence.r1.body_binding_sha256, - &evidence.r1.manifest_root_sha256, - &evidence.repo_model.identity.graph_id, - &evidence.repo_model.projection_digest, - &evidence.repo_model.source_documents, - &evidence.modeling_obligation_id, - &evidence.modeling_receipt_id, - &modeling.observed_vector_binding_root_sha256, - &coverage.receipt_id, - &coverage.observed_point_binding_set_sha256, - &coverage.observed_vector_binding_set_sha256, - observed_ready_at, - ))?; - Ok(RepositoryReadinessProjection { - schema_version: REPOSITORY_READINESS_PROJECTION_SCHEMA_VERSION.into(), - projection_id: format!("repository-readiness-{:x}", Sha256::digest(identity)), - status: "observed_ready_at".into(), - observed_ready_at: observed_ready_at.into(), - workspace_id: evidence.r1.workspace_id, - body_binding_sha256: evidence.r1.body_binding_sha256, - body_manifest_root_sha256: evidence.r1.manifest_root_sha256, - body_r1_observation_id: evidence.r1.observation_id, - body_r1_generation: evidence.r1.generation, - body_r2_observation_id: evidence.r2.observation_id, - body_r2_generation: evidence.r2.generation, - repo_model_graph_id: evidence.repo_model.identity.graph_id, - repo_model_projection_digest: evidence.repo_model.projection_digest, - repo_model_source_documents: evidence.repo_model.source_documents, - modeling_obligation_id: evidence.modeling_obligation_id, - modeling_receipt_id: evidence.modeling_receipt_id, - modeling_collection_name: modeling.collection_name, - modeling_observed_point_count: modeling.observed_point_count, - modeling_observed_vector_binding_root_sha256: modeling.observed_vector_binding_root_sha256, - workspace_policy_id: coverage.policy_id, - workspace_policy_sha256: coverage.policy_sha256, - workspace_coverage_receipt_id: coverage.receipt_id, - workspace_coverage_collection_name: coverage.collection_name, - workspace_coverage_observed_point_count: coverage.observed_point_count, - workspace_coverage_point_binding_set_sha256: coverage.observed_point_binding_set_sha256, - workspace_coverage_vector_binding_set_sha256: coverage.observed_vector_binding_set_sha256, - opening_non_body_authority_sha256: authority_sha256.clone(), - closing_non_body_authority_sha256: authority_sha256, - contract: "Historical Mind observation only. Current readiness must be rederived from fresh Body and live projection evidence.".into(), - swarm_id: r1.swarm_id.clone(), - runtime_id: r1.runtime_id.clone(), - body_scope: r1.scope.clone(), - truth_interval_started_at: r1.scan_finished_at.clone(), - truth_interval_closed_at: observed_ready_at.into(), - body_r1: r1, - body_r2: r2, - modeling_source_generation: evidence.modeling_source_generation, - modeling_canonical_content_set_hash: evidence.modeling_canonical_content_set_hash, - modeling_claim_id: evidence.modeling_claim_id, - modeling_claim_epoch: evidence.modeling_claim_epoch, - modeling_embedding_provider_id: evidence.modeling_embedding_provider_id, - modeling_embedding_model: evidence.modeling_embedding_model, - modeling_vector_dimensions: evidence.modeling_vector_dimensions, - modeling_receipt_envelope_sha256: evidence.modeling_receipt_envelope_sha256, - modeling_live_evidence_sha256: modeling_live_sha256, - workspace_obligation_envelope_sha256: coverage.obligation_envelope_digest, - workspace_plan_envelope_sha256: coverage.plan_envelope_digest, - workspace_claim_id: coverage.claim_id, - workspace_claim_epoch: coverage.claim_epoch, - workspace_claim_envelope_sha256: coverage.claim_envelope_digest, - workspace_attempt_id: coverage.attempt_id, - workspace_attempt_envelope_sha256: coverage.attempt_envelope_digest, - workspace_receipt_envelope_sha256: coverage.receipt_envelope_digest, - workspace_head_envelope_sha256: coverage.head_envelope_digest, - workspace_observed_point_set_sha256: coverage.observed_point_set_sha256, - modeling_obligation_envelope_sha256: evidence.modeling_obligation_envelope_sha256, - modeling_canonical_source_id: evidence.modeling_canonical_source_id, - modeling_source_commit_id: evidence.modeling_source_commit_id, - modeling_semantic_source_hash: evidence.modeling_semantic_source_hash, - modeling_current_content_set_hash: evidence.modeling_current_content_set_hash, - modeling_claim_envelope_sha256: evidence.modeling_claim_envelope_sha256, - modeling_attempt_id: evidence.modeling_attempt_id, - modeling_attempt_envelope_sha256: evidence.modeling_attempt_envelope_sha256, - workspace_embedding_provider_id: evidence.workspace_identity.embedding_provider_id, - workspace_embedding_model: evidence.workspace_identity.embedding_model, - workspace_vector_dimensions: evidence.workspace_identity.vector_dimensions, - workspace_obligation_id: coverage.obligation_id, - workspace_plan_id: coverage.plan_id, - }) -} - -fn readiness_authority_from_snapshot(rows: &[CultCacheEnvelope]) -> Vec { - rows.iter() - .cloned() - .filter(|row| { - row.r#type == crate::EpiphanyRuntimeSwarmBinding::TYPE - || row.r#type.starts_with("epiphany.mind.repo_model.") - || row.r#type == MemorySemanticProjectionObligation::TYPE - || row.r#type == MemorySemanticProjectionClaim::TYPE - || row.r#type == MemorySemanticProjectionAttempt::TYPE - || row.r#type == MemorySemanticIndexReceipt::TYPE - }) - .collect() -} - -fn decode_keyed_rows(rows: &[CultCacheEnvelope]) -> Result> { - rows.iter() - .filter(|row| row.r#type == T::TYPE) - .map(|row| Ok((row.key.clone(), rmp_serde::from_slice(&row.payload)?))) - .collect() -} - -fn exact_envelope<'a, T: DatabaseEntry>( - rows: &'a [CultCacheEnvelope], - key: &str, -) -> Result<&'a CultCacheEnvelope> { - rows.iter() - .find(|row| row.r#type == T::TYPE && row.key == key) - .ok_or_else(|| anyhow!("authority is missing {} envelope {key}", T::TYPE)) -} - -fn validate_repo_model_basis_against_snapshot( - model: &EpiphanyRepoModelView, - snapshot: &[CultCacheEnvelope], -) -> Result<()> { - let basis = model.reasoning_basis(); - basis.validate()?; - let mut sources = snapshot - .iter() - .filter(|row| row.r#type.starts_with("epiphany.mind.repo_model.")) - .map(|row| EpiphanyMindDocumentVersion::from_envelope("epiphany-mind", row)) - .collect::>>()?; - sources.sort_by(|left, right| { - (&left.document_type, &left.document_key).cmp(&(&right.document_type, &right.document_key)) - }); - if sources != basis.source_documents { - bail!("RepoModel basis does not seal the exact keyed store snapshot"); - } - Ok(()) -} - -fn derive_joined_opening( - snapshot: &[CultCacheEnvelope], - r1: &RepositoryBodyObservationBasis, - semantic: &RawSemanticObservation, - workspace_identity: &WorkspaceProjectionIdentity, -) -> Result { - let model = &semantic.repo_model; - validate_repo_model_basis_against_snapshot(model, snapshot)?; - if model.identity.workspace_id != r1.workspace_id - || model.identity.swarm_id != r1.swarm_id - || model.identity.runtime_id != r1.runtime_id - || model.identity.body_binding_sha256 != r1.body_binding_sha256 - { - bail!("current keyed RepoModel identity does not authenticate Body R1"); - } - validate_exact_raw_semantic_chain(r1, model, semantic)?; - for consumed in &semantic.authority_envelopes { - if !snapshot.contains(consumed) { - bail!("Modeling semantic authority is outside the exact store snapshot"); - } - } - let receipt_envelope = - exact_envelope::(snapshot, &semantic.receipt.receipt_id)?; - let receipt: MemorySemanticIndexReceipt = rmp_serde::from_slice(&receipt_envelope.payload)?; - let obligation_envelope = exact_envelope::( - snapshot, - &semantic.obligation.obligation_id, - )?; - let obligation: MemorySemanticProjectionObligation = - rmp_serde::from_slice(&obligation_envelope.payload)?; - if receipt != semantic.receipt || obligation != semantic.obligation { - bail!("Modeling semantic readiness is outside the exact store snapshot"); - } - let claims = decode_keyed_rows::(snapshot)? - .into_iter() - .filter(|(_, claim)| claim.claim_id == receipt.claim_id) - .collect::>(); - if claims.len() != 1 { - bail!("authority requires exactly one current semantic claim"); - } - let (claim_key, claim) = claims.into_iter().next().expect("one claim"); - if claim_key != claim.scope_id { - bail!("semantic claim is stored under an alien key"); - } - let claim_envelope = - exact_envelope::(snapshot, &claim.scope_id)?; - let attempt_envelope = - exact_envelope::(snapshot, &claim.attempt_id)?; - let attempt: MemorySemanticProjectionAttempt = - rmp_serde::from_slice(&attempt_envelope.payload)?; - if attempt.attempt_id != claim.attempt_id - || claim.status != "succeeded" - || claim.obligation_id != obligation.obligation_id - || claim.epoch != receipt.claim_epoch - || attempt.status != "succeeded" - || attempt.claim_id != claim.claim_id - || attempt.claim_epoch != claim.epoch - || attempt.obligation_id != claim.obligation_id - { - bail!("semantic claim/attempt chain is not the authenticated success chain"); - } - Ok(JoinedReadinessEvidence { - r1: r1.clone(), - r2: r1.clone(), - repo_model: model.clone(), - modeling_obligation_id: obligation.obligation_id.clone(), - modeling_receipt_id: receipt.receipt_id.clone(), - modeling_source_generation: receipt.source_generation, - modeling_canonical_content_set_hash: receipt.canonical_content_set_hash.clone(), - modeling_claim_id: receipt.claim_id.clone(), - modeling_claim_epoch: receipt.claim_epoch, - modeling_embedding_provider_id: receipt.embedding_provider_id.clone(), - modeling_embedding_model: receipt.embedding_model.clone(), - modeling_vector_dimensions: receipt.vector_dimensions, - modeling_receipt_envelope_sha256: envelope_sha256(receipt_envelope)?, - modeling_obligation_envelope_sha256: envelope_sha256(obligation_envelope)?, - modeling_canonical_source_id: obligation.canonical_source_id, - modeling_source_commit_id: obligation.source_commit_id, - modeling_semantic_source_hash: obligation.source_model_hash, - modeling_current_content_set_hash: semantic.current.canonical_content_set_hash.clone(), - modeling_claim_envelope_sha256: envelope_sha256(claim_envelope)?, - modeling_attempt_id: claim.attempt_id, - modeling_attempt_envelope_sha256: envelope_sha256(attempt_envelope)?, - workspace_identity: workspace_identity.clone(), - modeling_live: None, - coverage_live: None, - opening_authority: readiness_authority_from_snapshot(snapshot), - closing_authority: Vec::new(), - }) -} - -fn append_readiness_envelope_if_snapshot_unchanged( - backing: &SingleFileMessagePackBackingStore, - snapshot: &[CultCacheEnvelope], - envelope: CultCacheEnvelope, -) -> Result { - if backing.append_if_snapshot_unchanged(snapshot, vec![envelope.clone()])? { - return Ok(ReadinessAppendResult::Appended); - } - let mut actual = backing.pull_all()?; - let candidates = actual - .iter() - .enumerate() - .filter(|(_, row)| row.r#type == envelope.r#type && row.key == envelope.key) - .map(|(index, _)| index) - .collect::>(); - if candidates.len() == 1 { - let winner = actual.remove(candidates[0]); - actual.sort_by(|a, b| (&a.r#type, &a.key).cmp(&(&b.r#type, &b.key))); - let mut expected_baseline = snapshot.to_vec(); - expected_baseline.sort_by(|a, b| (&a.r#type, &a.key).cmp(&(&b.r#type, &b.key))); - if actual == expected_baseline && winner.payload == envelope.payload { - return Ok(ReadinessAppendResult::ConcurrentIdentical); - } - } - bail!("repository readiness authority changed before atomic projection append") -} - -struct ProductionReadinessPorts<'a> { - runtime_store: &'a Path, - semantic_config: &'a MemorySemanticIndexConfig, - workspace_identity: &'a WorkspaceProjectionIdentity, - close_clock: Option String + 'a>>, - pending_semantic: Option<( - MemorySemanticProjectionInput, - MemorySemanticProjectionReadiness, - )>, -} - -impl ReadinessObservationPorts for ProductionReadinessPorts<'_> { - fn observe_body(&mut self) -> Result { - observe_runtime_repository_body_basis(self.runtime_store) - } - - fn observe_store_snapshot(&mut self) -> Result> { - SingleFileMessagePackBackingStore::new(self.runtime_store) - .pull_all() - .map_err(Into::into) - } - - fn observe_semantic_state(&mut self) -> Result { - let input = runtime_modeling_semantic_projection_input(self.runtime_store)?; - let readiness = load_memory_semantic_projection_readiness(self.runtime_store, &input)? - .ok_or_else(|| anyhow!("current Modeling semantic projection is not ready"))?; - let repo_model = assemble_repo_model_view(self.runtime_store)?; - let raw = RawSemanticObservation { - semantic_content: RepoModelSemanticContent::from_semantic_input(&input), - repo_model, - authority_envelopes: input.authority.envelopes.clone(), - obligation: readiness.obligation.clone(), - current: readiness.current.clone(), - receipt: readiness.receipt.clone(), - }; - self.pending_semantic = Some((input, readiness)); - Ok(raw) - } - - fn observe_semantic_live(&mut self) -> Result> { - let (input, readiness) = self.pending_semantic.take().ok_or_else(|| { - anyhow!("semantic live observation requires raw semantic authority first") - })?; - observe_memory_semantic_live_evidence( - self.runtime_store, - self.semantic_config, - &input, - &readiness, - ) - } - - fn observe_workspace_live( - &mut self, - r1: &RepositoryBodyObservationBasis, - _opening: &JoinedReadinessEvidence, - ) -> Result> { - let mut backend = QdrantBackend::new(QdrantConfig { - url: self.workspace_identity.qdrant_url.clone(), - api_key: self.workspace_identity.qdrant_api_key.clone(), - timeout_ms: self.workspace_identity.qdrant_timeout_ms, - })?; - observe_current_workspace_coverage_evidence( - self.runtime_store, - r1, - &self.workspace_identity.policy, - &self.workspace_identity.embedding_provider_id, - &self.workspace_identity.embedding_model, - self.workspace_identity.vector_dimensions, - &mut backend, - ) - } - - fn close_time(&mut self) -> String { - self.close_clock.take().expect("close clock is called once")() - } - - fn append_projection( - &mut self, - snapshot: &[CultCacheEnvelope], - projection: &RepositoryReadinessProjection, - ) -> Result { - let mut cache = runtime_spine_cache(self.runtime_store)?; - cache.register_entry_type::()?; - cache.pull_all_backing_stores()?; - let (envelope, _) = cache.prepare_entry(&projection.projection_id, projection)?; - let backing = SingleFileMessagePackBackingStore::new(self.runtime_store); - append_readiness_envelope_if_snapshot_unchanged(&backing, snapshot, envelope) - } -} - -/// Derives and immutably records one Mind-owned whole-repository readiness -/// observation. The returned document is a receipt, never reusable admission. -pub fn observe_repository_readiness( - runtime_store: impl AsRef, - semantic_config: &MemorySemanticIndexConfig, - workspace_identity: &WorkspaceProjectionIdentity, -) -> Result { - observe_repository_readiness_with_clock( - runtime_store.as_ref(), - semantic_config, - workspace_identity, - || chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true), - ) -} - -fn observe_repository_readiness_with_clock( - runtime_store: &Path, - semantic_config: &MemorySemanticIndexConfig, - workspace_identity: &WorkspaceProjectionIdentity, - close_clock: impl FnOnce() -> String, -) -> Result { - let mut ports = ProductionReadinessPorts { - runtime_store, - semantic_config, - workspace_identity, - close_clock: Some(Box::new(close_clock)), - pending_semantic: None, - }; - observe_with_ports(&mut ports, workspace_identity) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Clone)] - struct FakePorts { - calls: Vec<&'static str>, - bodies: Vec, - snapshots: Vec>, - semantics: Vec, - semantic_live: Vec>, - coverage: Option, - closing_coverage: Option, - semantic_reads: usize, - coverage_reads: usize, - append: Result, - published: usize, - coverage_body_ids: Vec, - } - - impl ReadinessObservationPorts for FakePorts { - fn observe_body(&mut self) -> Result { - self.calls - .push(if self.bodies.len() == 2 { "r1" } else { "r2" }); - Ok(self.bodies.remove(0)) - } - - fn observe_store_snapshot(&mut self) -> Result> { - self.calls.push(if self.snapshots.len() == 2 { - "opening" - } else { - "closing-snapshot" - }); - Ok(self.snapshots.remove(0)) - } - - fn observe_semantic_state(&mut self) -> Result { - self.calls.push(if self.semantic_reads == 0 { - "semantic-state" - } else { - "closing-semantic-state" - }); - Ok(self.semantics.remove(0)) - } - - fn observe_semantic_live(&mut self) -> Result> { - self.calls.push(if self.semantic_reads == 0 { - "semantic" - } else { - "closing-semantic" - }); - self.semantic_reads += 1; - Ok(self.semantic_live.remove(0)) - } - - fn observe_workspace_live( - &mut self, - r1: &RepositoryBodyObservationBasis, - _opening: &JoinedReadinessEvidence, - ) -> Result> { - self.calls.push(if self.coverage_reads == 0 { - "coverage" - } else { - "closing-coverage" - }); - self.coverage_body_ids.push(r1.observation_id.clone()); - let value = if self.coverage_reads == 0 { - self.coverage.clone() - } else { - self.closing_coverage.clone() - }; - self.coverage_reads += 1; - Ok(value) - } - - fn close_time(&mut self) -> String { - self.calls.push("clock"); - "2026-07-16T01:00:00Z".into() - } - - fn append_projection( - &mut self, - _snapshot: &[CultCacheEnvelope], - _projection: &RepositoryReadinessProjection, - ) -> Result { - self.calls.push("append"); - match self.append { - Ok(ref result) => { - self.published += 1; - Ok(result.clone()) - } - Err(message) => bail!(message), - } - } - } - - fn basis(observation: &str, generation: u64, root: &str) -> RepositoryBodyObservationBasis { - RepositoryBodyObservationBasis { - schema_version: "gamecult.epiphany.repository_body_observation_basis.v0".into(), - workspace_id: "workspace".into(), - swarm_id: "swarm".into(), - runtime_id: "runtime".into(), - scope: "whole_repository".into(), - body_binding_sha256: "binding".into(), - observation_id: observation.into(), - generation, - manifest_root_sha256: root.into(), - scan_started_at: "2026-07-16T00:00:00Z".into(), - scan_finished_at: "2026-07-16T00:00:01Z".into(), - } - } - - fn envelope(key: &str, value: &T) -> CultCacheEnvelope { - CultCacheEnvelope { - key: key.into(), - r#type: T::TYPE.into(), - payload: rmp_serde::to_vec_named(value).unwrap(), - stored_at: "2026-07-16T00:00:00Z".into(), - schema_id: None, - } - } - - fn repo_model( - body: &RepositoryBodyObservationBasis, - ) -> Result<(Vec, EpiphanyRepoModelView)> { - let identity = crate::EpiphanyRepoModelIdentityDocument { - schema_epoch: crate::REPO_MODEL_SCHEMA_EPOCH.into(), - graph_id: "graph".into(), - runtime_id: body.runtime_id.clone(), - swarm_id: body.swarm_id.clone(), - workspace_id: body.workspace_id.clone(), - body_binding_sha256: body.body_binding_sha256.clone(), - }; - let identity_envelope = envelope(crate::REPO_MODEL_IDENTITY_KEY, &identity); - let source_documents = vec![EpiphanyMindDocumentVersion::from_envelope( - "epiphany-mind", - &identity_envelope, - )?]; - let projection_digest = format!( - "sha256:{:x}", - Sha256::digest(rmp_serde::to_vec_named(&source_documents)?) - ); - Ok(( - vec![identity_envelope], - EpiphanyRepoModelView { - identity, - projection_digest, - source_documents, - domains: Vec::new(), - nodes: Vec::new(), - edges: Vec::new(), - summaries: Vec::new(), - frontier: Vec::new(), - lifecycle_receipts: Vec::new(), - claim_obligations: Vec::new(), - surface_offers: Vec::new(), - dependency_claims: Vec::new(), - dependency_verifications: Vec::new(), - dependency_impacts: Vec::new(), - }, - )) - } - - fn raw_fixture( - body: RepositoryBodyObservationBasis, - ) -> Result<(Vec, RawSemanticObservation)> { - let (mut rows, model) = repo_model(&body)?; - let obligation = MemorySemanticProjectionObligation { - schema_version: MEMORY_SEMANTIC_PROJECTION_OBLIGATION_SCHEMA_VERSION.into(), - obligation_id: "semantic-obligation".into(), - swarm_id: "swarm".into(), - partition: "modeling".into(), - canonical_source_id: "source".into(), - source_commit_id: "commit".into(), - graph_id: model.identity.graph_id.clone(), - source_generation: 7, - source_model_hash: "semantic-model-hash".into(), - canonical_content_set_hash: "semantic-content".into(), - projection_schema_version: SEMANTIC_PROJECTION_SCHEMA_VERSION.into(), - created_at: "2026-07-16T00:00:00Z".into(), - }; - let current = MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }; - let receipt = MemorySemanticIndexReceipt { - schema_version: MEMORY_SEMANTIC_INDEX_RECEIPT_SCHEMA_VERSION.into(), - receipt_id: "semantic-receipt".into(), - swarm_id: "swarm".into(), - partition: "modeling".into(), - collection_name: "modeling".into(), - graph_id: model.identity.graph_id.clone(), - model_revision: 7, - model_hash: obligation.source_model_hash.clone(), - embedding_provider_id: "semantic-provider".into(), - embedding_model: "semantic-model".into(), - vector_dimensions: 1024, - indexed_document_count: 3, - deleted_document_count: 0, - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - indexed_at: "2026-07-16T00:00:00Z".into(), - status: "ready".into(), - obligation_id: obligation.obligation_id.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - source_generation: 7, - projection_schema_version: obligation.projection_schema_version.clone(), - claim_id: "semantic-claim".into(), - claim_epoch: 1, - observed_vector_binding_root_sha256: "0".repeat(64), - }; - let claim = MemorySemanticProjectionClaim { - schema_version: "claim-v0".into(), - scope_id: "modeling".into(), - claim_id: receipt.claim_id.clone(), - obligation_id: obligation.obligation_id.clone(), - attempt_id: "semantic-attempt".into(), - executor_id: "executor".into(), - epoch: 1, - status: "succeeded".into(), - claimed_at: "2026-07-16T00:00:00Z".into(), - completed_at: Some("2026-07-16T00:00:01Z".into()), - executor_incarnation: "incarnation".into(), - authority_kind: "test".into(), - authority_id: "authority".into(), - }; - let attempt = MemorySemanticProjectionAttempt { - schema_version: "attempt-v0".into(), - attempt_id: claim.attempt_id.clone(), - obligation_id: obligation.obligation_id.clone(), - started_at: "2026-07-16T00:00:00Z".into(), - completed_at: Some("2026-07-16T00:00:01Z".into()), - status: "succeeded".into(), - error: None, - claim_id: claim.claim_id.clone(), - claim_epoch: claim.epoch, - executor_id: claim.executor_id.clone(), - executor_incarnation: claim.executor_incarnation.clone(), - authority_id: claim.authority_id.clone(), - physical_backend_url: "http://qdrant".into(), - collection_name: "semantic-modeling".into(), - }; - rows.extend([ - envelope(&obligation.obligation_id, &obligation), - envelope(&receipt.receipt_id, &receipt), - envelope(&claim.scope_id, &claim), - envelope(&attempt.attempt_id, &attempt), - ]); - let raw = RawSemanticObservation { - semantic_content: RepoModelSemanticContent::from_repo_model(&model), - repo_model: model, - authority_envelopes: rows.clone(), - obligation, - current, - receipt, - }; - Ok((rows, raw)) - } - - fn joined( - r1: RepositoryBodyObservationBasis, - r2: RepositoryBodyObservationBasis, - ) -> JoinedReadinessEvidence { - let repo_model = repo_model(&r1).unwrap().1; - JoinedReadinessEvidence { - r1, - r2, - repo_model, - modeling_obligation_id: "semantic-obligation".into(), - modeling_receipt_id: "semantic-receipt".into(), - modeling_source_generation: 7, - modeling_canonical_content_set_hash: "semantic-content".into(), - modeling_claim_id: "semantic-claim".into(), - modeling_claim_epoch: 1, - modeling_embedding_provider_id: "semantic-provider".into(), - modeling_embedding_model: "semantic-model".into(), - modeling_vector_dimensions: 1024, - modeling_receipt_envelope_sha256: "semantic-receipt-envelope".into(), - modeling_obligation_envelope_sha256: "semantic-obligation-envelope".into(), - modeling_canonical_source_id: "source".into(), - modeling_source_commit_id: "commit".into(), - modeling_semantic_source_hash: "semantic-model-hash".into(), - modeling_current_content_set_hash: "semantic-content".into(), - modeling_claim_envelope_sha256: "semantic-claim-envelope".into(), - modeling_attempt_id: "semantic-attempt".into(), - modeling_attempt_envelope_sha256: "semantic-attempt-envelope".into(), - workspace_identity: WorkspaceProjectionIdentity { - policy: WorkspaceCoveragePolicy::bounded_regular_files_v0(1024).unwrap(), - qdrant_url: "http://workspace-qdrant".into(), - qdrant_api_key: None, - qdrant_timeout_ms: 1000, - embedding_provider_id: "workspace-provider".into(), - embedding_model: "workspace-model".into(), - vector_dimensions: 1024, - }, - modeling_live: Some(MemorySemanticLiveEvidence { - collection_name: "modeling".into(), - observed_point_count: 3, - observed_vector_binding_root_sha256: "semantic-root".into(), - }), - coverage_live: Some(WorkspaceCoverageReadinessEvidence { - workspace_id: "workspace".into(), - body_binding_sha256: "binding".into(), - manifest_root_sha256: "root-a".into(), - policy_id: "policy".into(), - policy_sha256: "policy-hash".into(), - obligation_id: "coverage-obligation".into(), - obligation_envelope_digest: "a".into(), - plan_id: "plan".into(), - plan_envelope_digest: "b".into(), - claim_id: "claim".into(), - claim_epoch: 1, - claim_envelope_digest: "c".into(), - attempt_id: "attempt".into(), - attempt_envelope_digest: "d".into(), - receipt_id: "coverage-receipt".into(), - receipt_envelope_digest: "e".into(), - head_envelope_digest: "f".into(), - collection_name: "coverage".into(), - observed_point_count: 9, - observed_point_set_sha256: "points".into(), - observed_point_binding_set_sha256: "bindings".into(), - observed_vector_binding_set_sha256: "vectors".into(), - }), - opening_authority: Vec::new(), - closing_authority: Vec::new(), - } - } - - fn fake_ports( - r1: RepositoryBodyObservationBasis, - r2: RepositoryBodyObservationBasis, - ) -> Result { - let opening = joined(r1.clone(), r1.clone()); - let (rows, raw) = raw_fixture(r1.clone())?; - Ok(FakePorts { - calls: Vec::new(), - bodies: vec![r1, r2], - snapshots: vec![rows.clone(), rows], - semantics: vec![raw.clone(), raw], - semantic_live: vec![opening.modeling_live.clone(), opening.modeling_live.clone()], - coverage: opening.coverage_live.clone(), - closing_coverage: opening.coverage_live.clone(), - semantic_reads: 0, - coverage_reads: 0, - append: Ok(ReadinessAppendResult::Appended), - published: 0, - coverage_body_ids: Vec::new(), - }) - } - - #[test] - fn orchestration_uses_exact_two_read_interval_and_r1_bound_coverage() -> Result<()> { - let r1 = basis("observation-a1", 1, "root-a"); - let r2 = basis("observation-a2", 3, "root-a"); - let mut ports = fake_ports(r1.clone(), r2)?; - let identity = joined(r1.clone(), r1.clone()).workspace_identity; - let projection = observe_with_ports(&mut ports, &identity)?; - assert_eq!(projection.body_r1_observation_id, "observation-a1"); - assert_eq!(projection.body_r2_observation_id, "observation-a2"); - assert_eq!( - ports.coverage_body_ids, - vec![r1.observation_id.clone(), r1.observation_id] - ); - assert_eq!( - ports.calls, - vec![ - "r1", - "opening", - "semantic-state", - "semantic", - "coverage", - "r2", - "closing-semantic-state", - "closing-semantic", - "closing-coverage", - "closing-snapshot", - "clock", - "append" - ] - ); - Ok(()) - } - - #[test] - fn body_or_closing_authority_drift_never_reaches_append() { - let r1 = basis("a1", 1, "root-a"); - let mut body_drift = fake_ports(r1.clone(), basis("b", 2, "root-b")).unwrap(); - let identity = joined(r1.clone(), r1.clone()).workspace_identity; - assert!(observe_with_ports(&mut body_drift, &identity).is_err()); - assert!(!body_drift.calls.contains(&"append")); - - let mut authority_drift = fake_ports(r1.clone(), basis("a2", 2, "root-a")).unwrap(); - authority_drift.snapshots[1].push(CultCacheEnvelope { - key: "alien".into(), - r#type: crate::EpiphanyRepoModelIdentityDocument::TYPE.into(), - payload: vec![1], - stored_at: "2026-07-16T00:00:02Z".into(), - schema_id: None, - }); - assert!(observe_with_ports(&mut authority_drift, &identity).is_err()); - assert!(!authority_drift.calls.contains(&"append")); - } - - #[test] - fn raw_opening_incomplete_or_tampered_keyed_model_is_rejected_before_live_queries() { - let r1 = basis("a1", 1, "root-a"); - let identity = joined(r1.clone(), r1.clone()).workspace_identity; - let mut incomplete = fake_ports(r1.clone(), basis("a2", 2, "root-a")).unwrap(); - incomplete.snapshots[0] - .retain(|row| row.r#type != crate::EpiphanyRepoModelIdentityDocument::TYPE); - assert!(observe_with_ports(&mut incomplete, &identity).is_err()); - assert!(!incomplete.calls.contains(&"semantic")); - - let mut tampered = fake_ports(r1.clone(), basis("a2", 2, "root-a")).unwrap(); - tampered.snapshots[0] - .iter_mut() - .find(|row| row.r#type == crate::EpiphanyRepoModelIdentityDocument::TYPE) - .unwrap() - .payload - .push(0); - assert!(observe_with_ports(&mut tampered, &identity).is_err()); - assert!(!tampered.calls.contains(&"semantic")); - } - - #[test] - fn raw_semantic_cross_field_forgery_is_rejected_before_live_query() { - let r1 = basis("a1", 1, "root-a"); - let identity = joined(r1.clone(), r1.clone()).workspace_identity; - let mut head_forgery = fake_ports(r1.clone(), basis("a2", 2, "root-a")).unwrap(); - head_forgery.semantics[0].current.canonical_content_set_hash = "alien-content".into(); - assert!(observe_with_ports(&mut head_forgery, &identity).is_err()); - assert!(!head_forgery.calls.contains(&"semantic")); - - let mut receipt_forgery = fake_ports(r1.clone(), basis("a2", 2, "root-a")).unwrap(); - receipt_forgery.semantics[0].receipt.source_commit_id = "alien-commit".into(); - assert!(observe_with_ports(&mut receipt_forgery, &identity).is_err()); - assert!(!receipt_forgery.calls.contains(&"semantic")); - } - - #[test] - fn cas_refusal_returns_no_success_and_identical_concurrent_append_is_accepted() -> Result<()> { - let r1 = basis("a1", 1, "root-a"); - let r2 = basis("a2", 2, "root-a"); - let mut refused = fake_ports(r1.clone(), r2.clone())?; - let identity = joined(r1.clone(), r1.clone()).workspace_identity; - refused.append = Err("CAS refused"); - assert!(observe_with_ports(&mut refused, &identity).is_err()); - assert_eq!(refused.published, 0); - - let mut identical = fake_ports(r1, r2)?; - identical.append = Ok(ReadinessAppendResult::ConcurrentIdentical); - observe_with_ports(&mut identical, &identity)?; - assert_eq!(identical.published, 1); - Ok(()) - } - - fn raw_envelope(kind: &str, key: &str, payload: u8) -> CultCacheEnvelope { - CultCacheEnvelope { - key: key.into(), - r#type: kind.into(), - payload: vec![payload], - stored_at: "2026-07-16T00:00:00Z".into(), - schema_id: None, - } - } - - #[test] - fn real_append_primitive_distinguishes_exact_and_hostile_concurrency() -> Result<()> { - let run = |concurrent: Option| -> Result { - let temp = tempfile::tempdir()?; - let path = temp.path().join("state.msgpack"); - let mut backing = SingleFileMessagePackBackingStore::new(&path); - let baseline = raw_envelope("baseline", "one", 1); - backing.push(&baseline)?; - let snapshot = backing.pull_all()?; - if let Some(row) = concurrent { - backing.push(&row)?; - } - append_readiness_envelope_if_snapshot_unchanged( - &backing, - &snapshot, - raw_envelope(REPOSITORY_READINESS_PROJECTION_TYPE, "projection", 7), - ) - }; - - assert_eq!( - run(None).map_err(|e| anyhow!("exact append: {e}"))?, - ReadinessAppendResult::Appended - ); - assert_eq!( - run(Some(raw_envelope( - REPOSITORY_READINESS_PROJECTION_TYPE, - "projection", - 7 - ))) - .map_err(|e| anyhow!("identical concurrent: {e}"))?, - ReadinessAppendResult::ConcurrentIdentical - ); - assert!(run(Some(raw_envelope("unrelated", "row", 9))).is_err()); - assert!( - run(Some(raw_envelope( - REPOSITORY_READINESS_PROJECTION_TYPE, - "projection", - 8 - ))) - .is_err() - ); - Ok(()) - } - - #[test] - fn missing_semantic_or_stored_only_coverage_cannot_substitute_for_live_evidence() { - let body = basis("a", 1, "root-a"); - let mut missing_semantic = joined(body.clone(), body.clone()); - missing_semantic.modeling_live = None; - assert!(projection_from_join(missing_semantic, "2026-07-16T01:00:00Z").is_err()); - let mut stored_only_coverage = joined(body.clone(), body); - stored_only_coverage.coverage_live = None; - assert!(projection_from_join(stored_only_coverage, "2026-07-16T01:00:00Z").is_err()); - } - - #[test] - fn body_change_and_non_body_authority_advance_are_refused() { - let a = basis("a", 1, "root-a"); - let b = basis("b", 2, "root-b"); - assert!(projection_from_join(joined(a.clone(), b), "2026-07-16T01:00:00Z").is_err()); - let mut advanced = joined(a.clone(), a); - advanced.closing_authority.push(CultCacheEnvelope { - key: "duplicate".into(), - r#type: "epiphany.mind.repo_model.node.v1".into(), - payload: vec![1], - stored_at: "2026-07-16T00:00:02Z".into(), - schema_id: None, - }); - assert!(projection_from_join(advanced, "2026-07-16T01:00:00Z").is_err()); - } - - #[test] - fn a_to_b_to_a_is_accepted_when_final_content_identity_is_equal() -> Result<()> { - let r1 = basis("observation-a1", 1, "root-a"); - let r2 = basis("observation-a2", 3, "root-a"); - let projection = projection_from_join(joined(r1, r2), "2026-07-16T01:00:00Z")?; - assert_eq!(projection.status, "observed_ready_at"); - assert_eq!(projection.body_r2_generation, 3); - Ok(()) - } - - #[test] - fn proof_close_time_cannot_predate_r2() { - let body = basis("a", 1, "root-a"); - assert!(projection_from_join(joined(body.clone(), body), "2026-07-15T23:59:59Z").is_err()); - } -} diff --git a/epiphany-core/src/runtime_spine.rs b/epiphany-core/src/runtime_spine.rs index 8370a7bb..60d424f5 100644 --- a/epiphany-core/src/runtime_spine.rs +++ b/epiphany-core/src/runtime_spine.rs @@ -990,15 +990,6 @@ pub fn runtime_spine_cache(store_path: impl AsRef) -> Result { cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; - cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; @@ -1012,9 +1003,7 @@ pub fn runtime_spine_cache(store_path: impl AsRef) -> Result { cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; - cache.register_entry_type::()?; cache.register_entry_type::()?; - cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; @@ -1253,25 +1242,6 @@ pub fn runtime_swarm_binding( cache.get(RUNTIME_SWARM_BINDING_KEY) } -fn require_runtime_swarm_binding(cache: &CultCache) -> Result { - let identity = require_identity(cache)?; - let binding = cache - .get::(RUNTIME_SWARM_BINDING_KEY)? - .ok_or_else(|| anyhow!("RepoModel admission requires immutable runtime swarm binding"))?; - if binding.schema_version != RUNTIME_SWARM_BINDING_SCHEMA_VERSION - || binding.binding_id != RUNTIME_SWARM_BINDING_KEY - || binding.runtime_id != identity.runtime_id - || binding.swarm_id.trim().is_empty() - || binding.source_identity_type != RUNTIME_IDENTITY_TYPE - || binding.source_identity_key != RUNTIME_IDENTITY_KEY - || binding.source_identity_sha256.trim().is_empty() - || chrono::DateTime::parse_from_rfc3339(&binding.bound_at).is_err() - { - return Err(anyhow!("runtime swarm binding is invalid")); - } - Ok(binding) -} - pub fn create_runtime_session( store_path: impl AsRef, options: RuntimeSpineSessionOptions, @@ -6349,133 +6319,6 @@ fn keyed_repo_model_basis_after_writes( Ok(basis) } -pub fn runtime_modeling_semantic_projection_input( - store_path: impl AsRef, -) -> Result { - let store_path = store_path.as_ref(); - // Projection work is cache physiology, not a Mind commit companion. A - // singleton companion would make otherwise-disjoint RepoModel commits - // contend. Reconstruct the exact current keyed basis on every pulse and - // insert its content-addressed work item under the same envelope CAS used - // by the projector. Concurrent inserts can create an older work item, but - // cannot make it current; the next pulse derives the newly assembled view. - for _ in 0..8 { - let mut cache = runtime_spine_cache(store_path)?; - cache.pull_all_backing_stores()?; - let binding = require_runtime_swarm_binding(&cache)?; - let view = crate::repo_model_documents::assemble_repo_model_view_from_cache(&cache)?; - if view.identity.runtime_id != binding.runtime_id - || view.identity.swarm_id != binding.swarm_id - { - return Err(anyhow!( - "RepoModel semantic basis crossed its runtime swarm binding" - )); - } - let basis = view.reasoning_basis(); - basis.validate_against_cache(&cache)?; - let mut snapshot = view.memory_context_projection(); - // This is a compatibility-shaped projector DTO, never a causal head. - // Keyed document versions and their commit receipts own the input. - snapshot.model_revision = 1; - snapshot.model_hash = crate::memory_graph_model_hash(&snapshot)?; - - let mut authority_envelopes = keyed_repo_model_basis_envelopes(&cache, &basis)?; - let receipts = repo_model_basis_commit_receipts(&cache, &basis)?; - if receipts.is_empty() { - return Err(anyhow!( - "RepoModel semantic basis has no Mind commit receipts" - )); - } - for receipt in &receipts { - authority_envelopes.push( - cache - .get_envelope::(&receipt.receipt_id)? - .ok_or_else(|| anyhow!("RepoModel semantic basis receipt disappeared"))?, - ); - } - authority_envelopes.push( - cache - .get_envelope::(RUNTIME_SWARM_BINDING_KEY)? - .ok_or_else(|| anyhow!("Modeling projection lost its swarm binding"))?, - ); - authority_envelopes - .sort_by(|left, right| (&left.r#type, &left.key).cmp(&(&right.r#type, &right.key))); - authority_envelopes - .dedup_by(|left, right| left.r#type == right.r#type && left.key == right.key); - - let obligation = - crate::repo_model_documents::derive_repo_model_semantic_projection_obligation( - &view, - // Modeling cache work is content-addressed by the complete - // keyed basis. Wall-clock receipt order is not causal state. - "1970-01-01T00:00:00Z", - )?; - if let Some(persisted) = - cache.get::(&obligation.obligation_id)? - { - if persisted != obligation { - return Err(anyhow!("Modeling projection obligation identity collision")); - } - return Ok(crate::MemorySemanticProjectionInput { - snapshot, - authority: crate::memory_graph::MemorySemanticProjectionAuthoritySnapshot { - head: crate::MemorySemanticProjectionSourceHead { - swarm_id: obligation.swarm_id.clone(), - partition: obligation.partition.clone(), - canonical_source_id: obligation.canonical_source_id.clone(), - source_commit_id: obligation.source_commit_id.clone(), - graph_id: obligation.graph_id.clone(), - source_generation: obligation.source_generation, - source_model_hash: obligation.source_model_hash.clone(), - canonical_content_set_hash: obligation.canonical_content_set_hash.clone(), - }, - envelopes: authority_envelopes, - }, - obligation, - }); - } - - let mut replacements = authority_envelopes.clone(); - replacements.push( - cache - .prepare_entry(&obligation.obligation_id, &obligation)? - .0, - ); - if runtime_spine_backing_store(store_path)? - .compare_and_swap_batch(&authority_envelopes, replacements)? - { - continue; - } - } - Err(anyhow!( - "RepoModel semantic work could not settle under concurrent Mind mutation" - )) -} - -fn repo_model_basis_commit_receipts( - cache: &CultCache, - basis: &crate::EpiphanyRepoModelBasis, -) -> Result> { - basis.validate_against_cache(cache)?; - let receipts = cache.get_all::()?; - let mut owners = BTreeMap::::new(); - for source in &basis.source_documents { - let owner = receipts - .iter() - .filter(|receipt| receipt.writes.iter().any(|write| write == source)) - .min_by(|left, right| left.receipt_id.cmp(&right.receipt_id)) - .ok_or_else(|| { - anyhow!( - "RepoModel document {}:{} has no exact Mind commit receipt", - source.document_type, - source.document_key - ) - })?; - owners.insert(owner.receipt_id.clone(), owner.clone()); - } - Ok(owners.into_values().collect()) -} - pub fn select_repo_frontier_work_proposal_for_modeling( store_path: impl AsRef, proposal_id: &str, diff --git a/epiphany-core/src/semantic_backend.rs b/epiphany-core/src/semantic_backend.rs deleted file mode 100644 index e3cc67a3..00000000 --- a/epiphany-core/src/semantic_backend.rs +++ /dev/null @@ -1,1018 +0,0 @@ -//! Typed boundary around the Qdrant and Ollama HTTP APIs. -//! -//! JSON is deliberately confined to this xenos-facing module. Callers provide -//! typed collection contracts, points, and payloads; Qdrant remains a -//! rebuildable projection rather than canonical authority. - -use anyhow::{Context, Result}; -use reqwest::blocking::{Client, ClientBuilder, Response}; -use reqwest::header::{HeaderMap, HeaderValue}; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; -use serde_json::{Value, json}; -use std::collections::{HashMap, HashSet}; -use std::time::Duration; - -pub(crate) const QDRANT_POINT_BATCH_MAX: usize = 128; -const EMBED_BATCH_SIZE: usize = 4; - -#[derive(Clone, Debug)] -pub(crate) struct QdrantConfig { - pub(crate) url: String, - pub(crate) api_key: Option, - pub(crate) timeout_ms: u64, -} - -#[derive(Clone, Debug)] -pub(crate) struct OllamaConfig { - pub(crate) base_url: String, - pub(crate) model: String, - pub(crate) timeout_ms: u64, - pub(crate) query_instruction: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct OllamaModelArtifact { - pub(crate) tag: String, - pub(crate) digest: String, -} - -impl OllamaModelArtifact { - pub(crate) fn canonical_identity(&self) -> String { - format!("{}@{}", self.tag, self.digest) - } -} - -/// Exact identity of a managed semantic projection. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub(crate) struct CollectionCompatibility { - pub(crate) managed_by: String, - pub(crate) corpus_kind: String, - pub(crate) schema_version: u32, - pub(crate) projection_version: String, - pub(crate) embedding_provider_id: String, - pub(crate) embedding_model: String, - pub(crate) vector_size: usize, -} - -#[derive(Clone, Debug, Serialize)] -pub(crate) struct SemanticPoint

{ - pub(crate) id: String, - pub(crate) vector: Vec, - pub(crate) payload: P, -} - -#[derive(Clone, Debug, PartialEq)] -pub(crate) struct SemanticCandidate

{ - pub(crate) score: f32, - pub(crate) payload: Option

, -} - -#[derive(Clone, Debug, PartialEq)] -pub(crate) struct SemanticStoredPoint

{ - pub(crate) id: String, - pub(crate) payload: Option

, - pub(crate) vector: Option>, -} - -/// Transport acknowledgement only. This proves that Qdrant completed one -/// waited operation; it does not prove any domain projection invariant. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct QdrantCompletedAcknowledgement { - pub(crate) operation_id: u64, -} - -pub(crate) struct QdrantBackend { - base_url: String, - timeout_seconds: u64, - client: Client, -} - -impl QdrantBackend { - pub(crate) fn new(config: QdrantConfig) -> Result { - let mut headers = HeaderMap::new(); - if let Some(api_key) = config.api_key.filter(|key| !key.is_empty()) { - headers.insert( - "api-key", - HeaderValue::from_str(&api_key).context("invalid Qdrant api key")?, - ); - } - let client = ClientBuilder::new() - .default_headers(headers) - .timeout(Duration::from_millis(config.timeout_ms)) - .build() - .context("failed to build Qdrant client")?; - Ok(Self { - base_url: normalize_base_url(&config.url), - timeout_seconds: timeout_seconds(config.timeout_ms), - client, - }) - } - - pub(crate) fn collection_exists(&self, name: &str) -> Result { - let response = self - .client - .get(format!("{}/collections/{name}/exists", self.base_url)) - .send() - .with_context(|| format!("failed to query Qdrant collection {name}"))?; - let envelope: Envelope = parse_response(response).with_context(|| { - format!("failed to decode Qdrant collection-exists response for {name}") - })?; - Ok(envelope.result.exists) - } - - /// Reads the compatibility contract Qdrant stores with the collection. - /// Missing or malformed metadata is an error, never implicit compatibility. - pub(crate) fn collection_compatibility(&self, name: &str) -> Result { - let response = self - .client - .get(format!("{}/collections/{name}", self.base_url)) - .send() - .with_context(|| format!("failed to inspect Qdrant collection {name}"))?; - let envelope: Envelope = parse_response(response) - .with_context(|| format!("failed to decode Qdrant collection metadata for {name}"))?; - envelope - .result - .config - .metadata - .context("managed Qdrant collection has no compatibility metadata") - } - - pub(crate) fn create_collection( - &self, - name: &str, - contract: &CollectionCompatibility, - ) -> Result<()> { - if contract.vector_size == 0 { - anyhow::bail!("collection vector size must be greater than zero"); - } - let body = json!({ - "vectors": { "size": contract.vector_size, "distance": "Cosine", "on_disk": true }, - "on_disk_payload": true, - "metadata": contract, - }); - let response = self - .client - .put(format!("{}/collections/{name}", self.base_url)) - .query(&[("timeout", self.timeout_seconds)]) - .json(&body) - .send() - .with_context(|| format!("failed to create Qdrant collection {name}"))?; - parse_response::(response).with_context(|| { - format!("failed to decode Qdrant create-collection response for {name}") - })?; - Ok(()) - } - - /// Ensures a collection exists under one exact managed contract. A - /// concurrent creator may win between exists/create; that is acceptable - /// only when the collection it created has the identical contract. - pub(crate) fn ensure_exact_collection( - &self, - name: &str, - contract: &CollectionCompatibility, - ) -> Result<()> { - if !self.collection_exists(name)? { - if let Err(create_error) = self.create_collection(name, contract) { - if !self.collection_exists(name)? { - return Err(create_error).with_context(|| { - format!("failed to create managed Qdrant collection {name}") - }); - } - } - } - if self.collection_compatibility(name)? != *contract { - anyhow::bail!("managed Qdrant collection {name} has incompatible metadata"); - } - Ok(()) - } - - /// Deletes only the exact managed projection named by `contract`. - /// Absence is already the retired state; incompatible metadata is never - /// overwritten or deleted merely because its name collides. - pub(crate) fn retire_exact_collection( - &self, - name: &str, - contract: &CollectionCompatibility, - ) -> Result<()> { - if !self.collection_exists(name)? { - return Ok(()); - } - if self.collection_compatibility(name)? != *contract { - anyhow::bail!("refusing to retire Qdrant collection {name} with incompatible metadata"); - } - let response = self - .client - .delete(format!("{}/collections/{name}", self.base_url)) - .query(&[("timeout", self.timeout_seconds)]) - .send() - .with_context(|| format!("failed to retire Qdrant collection {name}"))?; - parse_response::(response) - .with_context(|| format!("failed to decode Qdrant retirement response for {name}"))?; - Ok(()) - } - - pub(crate) fn upsert_points( - &self, - name: &str, - points: &[SemanticPoint

], - ) -> Result<()> { - validate_point_batch(points)?; - for batch in points.chunks(QDRANT_POINT_BATCH_MAX) { - self.upsert_point_batch_waited(name, batch)?; - } - Ok(()) - } - - pub(crate) fn upsert_point_batch_waited( - &self, - name: &str, - points: &[SemanticPoint

], - ) -> Result { - if points.is_empty() { - anyhow::bail!("Qdrant waited upsert batch must not be empty"); - } - if points.len() > QDRANT_POINT_BATCH_MAX { - anyhow::bail!( - "Qdrant waited upsert batch exceeds canonical maximum {QDRANT_POINT_BATCH_MAX}" - ); - } - validate_point_batch(points)?; - let response = self - .client - .put(format!("{}/collections/{name}/points", self.base_url)) - .query(&[ - ("wait", "true"), - ("timeout", &self.timeout_seconds.to_string()), - ]) - .json(&json!({ "points": points })) - .send() - .with_context(|| format!("failed to upsert Qdrant points into {name}"))?; - let envelope: Envelope = parse_response(response) - .with_context(|| format!("failed to decode Qdrant upsert response for {name}"))?; - validate_completed_acknowledgement(envelope.result) - } - - pub(crate) fn delete_points(&self, name: &str, point_ids: &[String]) -> Result<()> { - for batch in point_ids.chunks(QDRANT_POINT_BATCH_MAX) { - let response = self - .client - .post(format!( - "{}/collections/{name}/points/delete", - self.base_url - )) - .query(&[ - ("wait", "true"), - ("timeout", &self.timeout_seconds.to_string()), - ]) - .json(&json!({ "points": batch })) - .send() - .with_context(|| format!("failed to delete Qdrant points from {name}"))?; - parse_response::(response).with_context(|| { - format!("failed to decode Qdrant delete-points response for {name}") - })?; - } - Ok(()) - } - - pub(crate) fn retrieve_points_by_ids( - &self, - name: &str, - point_ids: &[String], - ) -> Result>> { - validate_requested_point_ids(point_ids)?; - let response = self - .client - .post(format!("{}/collections/{name}/points", self.base_url)) - .query(&[("timeout", self.timeout_seconds)]) - .json(&json!({ - "ids": point_ids, - "with_payload": true, - "with_vector": true, - })) - .send() - .with_context(|| format!("failed to retrieve exact Qdrant points from {name}"))?; - let envelope: Envelope>> = parse_response(response) - .with_context(|| format!("failed to decode exact Qdrant points from {name}"))?; - order_and_validate_retrieved_points(point_ids, envelope.result) - } - - pub(crate) fn query_points_for_scope( - &self, - name: &str, - vector: &[f32], - limit: usize, - scope: &[(&str, &str)], - ) -> Result>> { - if vector.is_empty() { - anyhow::bail!("query vector must not be empty"); - } - if limit == 0 { - return Ok(Vec::new()); - } - let must = scope - .iter() - .map(|(key, value)| json!({ "key": key, "match": { "value": value } })) - .collect::>(); - let response = self.client.post(format!("{}/collections/{name}/points/query", self.base_url)) - .query(&[("timeout", self.timeout_seconds)]) - .json(&json!({ "query": vector, "filter": { "must": must }, "limit": limit, "with_payload": true, "with_vector": false })) - .send().with_context(|| format!("failed to query Qdrant collection {name}"))?; - let envelope: Envelope> = parse_response(response) - .with_context(|| format!("failed to decode Qdrant query response for {name}"))?; - Ok(envelope - .result - .points - .into_iter() - .map(|point| SemanticCandidate { - score: point.score, - payload: point.payload, - }) - .collect()) - } - - pub(crate) fn point_ids_for_scope( - &self, - name: &str, - scope: &[(&str, &str)], - ) -> Result> { - let must = scope - .iter() - .map(|(key, value)| json!({ "key": key, "match": { "value": value } })) - .collect::>(); - let mut offset: Option = None; - let mut seen_offsets = Vec::::new(); - let mut ids = Vec::new(); - loop { - let response = self - .client - .post(format!( - "{}/collections/{name}/points/scroll", - self.base_url - )) - .query(&[("timeout", self.timeout_seconds)]) - .json(&json!({ - "filter": { "must": must }, - "limit": QDRANT_POINT_BATCH_MAX, - "offset": offset, - "with_payload": false, - "with_vector": false, - })) - .send() - .with_context(|| format!("failed to scroll Qdrant scope in {name}"))?; - let envelope: Envelope = parse_response(response) - .with_context(|| format!("failed to decode Qdrant scroll response for {name}"))?; - ids.extend(envelope.result.points.into_iter().map(|point| point.id)); - offset = envelope.result.next_page_offset; - if let Some(next_offset) = offset.as_ref() { - if seen_offsets.contains(next_offset) { - anyhow::bail!("Qdrant scroll repeated a prior page offset for {name}"); - } - seen_offsets.push(next_offset.clone()); - } - if offset.is_none() { - break; - } - } - Ok(ids) - } - - pub(crate) fn points_for_scope( - &self, - name: &str, - scope: &[(&str, &str)], - ) -> Result>> { - let must = scope - .iter() - .map(|(key, value)| json!({ "key": key, "match": { "value": value } })) - .collect::>(); - let mut offset: Option = None; - let mut seen_offsets = Vec::::new(); - let mut points = Vec::new(); - loop { - let response = self - .client - .post(format!( - "{}/collections/{name}/points/scroll", - self.base_url - )) - .query(&[("timeout", self.timeout_seconds)]) - .json(&json!({ - "filter": { "must": must }, - "limit": QDRANT_POINT_BATCH_MAX, - "offset": offset, - "with_payload": true, - "with_vector": true, - })) - .send() - .with_context(|| format!("failed to observe Qdrant scope in {name}"))?; - let envelope: Envelope> = parse_response(response) - .with_context(|| format!("failed to decode Qdrant scope payloads in {name}"))?; - points.extend( - envelope - .result - .points - .into_iter() - .map(|point| SemanticStoredPoint { - id: point.id, - payload: point.payload, - vector: point.vector, - }), - ); - offset = envelope.result.next_page_offset; - if let Some(next_offset) = offset.as_ref() { - if seen_offsets.contains(next_offset) { - anyhow::bail!("Qdrant payload scroll repeated a prior page offset for {name}"); - } - seen_offsets.push(next_offset.clone()); - } - if offset.is_none() { - break; - } - } - Ok(points) - } -} - -pub(crate) struct OllamaEmbedder { - base_url: String, - model: String, - query_instruction: String, - client: Client, -} - -impl OllamaEmbedder { - pub(crate) fn new(config: OllamaConfig) -> Result { - let client = ClientBuilder::new() - .timeout(Duration::from_millis(config.timeout_ms)) - .build() - .context("failed to build Ollama client")?; - Ok(Self { - base_url: normalize_base_url(&config.base_url), - model: config.model, - query_instruction: config.query_instruction, - client, - }) - } - - pub(crate) fn embed_documents(&self, texts: &[String]) -> Result>> { - let mut embeddings = Vec::new(); - for batch in texts.chunks(EMBED_BATCH_SIZE) { - embeddings.extend(self.embed_batch(batch)?); - } - validate_embedding_batch(&embeddings, texts.len())?; - Ok(embeddings) - } - - /// Resolves the configured mutable Ollama tag to the immutable artifact - /// digest currently installed behind it. Projection identity must use this - /// value; embedding requests continue to use the configured tag. - pub(crate) fn model_artifact(&self) -> Result { - let response = self - .client - .get(format!("{}/api/tags", self.base_url)) - .send() - .with_context(|| format!("failed to inspect Ollama models at {}", self.base_url))?; - let status = response.status(); - if !status.is_success() { - let body = response.text().unwrap_or_default(); - anyhow::bail!("Ollama model inspection failed with {status}: {body}"); - } - let tags: OllamaTagsResponse = response.json().with_context(|| { - format!("failed to decode Ollama model tags from {}", self.base_url) - })?; - let mut matches = tags - .models - .into_iter() - .filter(|candidate| candidate.name == self.model || candidate.model == self.model) - .collect::>(); - if matches.len() != 1 { - anyhow::bail!( - "configured Ollama model {} resolved to {} installed artifacts", - self.model, - matches.len() - ); - } - let candidate = matches.pop().expect("validated one artifact"); - let digest = normalize_ollama_digest(&candidate.digest)?; - Ok(OllamaModelArtifact { - tag: self.model.clone(), - digest, - }) - } - - pub(crate) fn embed_query(&self, query: &str) -> Result> { - let formatted = format!("Instruct: {}\nQuery: {}", self.query_instruction, query); - let mut embeddings = self.embed_batch(&[formatted])?; - validate_embedding_batch(&embeddings, 1)?; - Ok(embeddings.pop().expect("validated one embedding")) - } - - pub(crate) fn embedding_dimensions(&self) -> Result { - const DIMENSION_PROBE: &str = "epiphany embedding dimension probe v0"; - - let embeddings = self.embed_batch(&[DIMENSION_PROBE.to_string()])?; - if embeddings.len() != 1 { - anyhow::bail!( - "Ollama dimension probe returned {} vectors instead of one", - embeddings.len() - ); - } - let vector = &embeddings[0]; - if vector.is_empty() { - anyhow::bail!("Ollama dimension probe returned an empty vector"); - } - if vector.iter().any(|value| !value.is_finite()) { - anyhow::bail!("Ollama dimension probe returned a non-finite value"); - } - u32::try_from(vector.len()).context("Ollama embedding dimensions exceed u32") - } - - fn embed_batch(&self, texts: &[String]) -> Result>> { - let response = self - .client - .post(format!("{}/api/embed", self.base_url)) - .json(&json!({ "model": self.model, "input": texts })) - .send() - .with_context(|| { - format!( - "failed to contact Ollama at {} using model {}", - self.base_url, self.model - ) - })?; - if !response.status().is_success() { - let status = response.status(); - let body = response.text().unwrap_or_default(); - anyhow::bail!( - "Ollama embedding request failed with {status}: {body}. Make sure Ollama is running at {} and model {} is available", - self.base_url, - self.model - ); - } - let payload: EmbedResponse = response.json().with_context(|| { - format!( - "failed to decode Ollama embedding response from {}", - self.base_url - ) - })?; - payload - .embeddings - .context("Ollama embedding response did not include embeddings") - } -} - -pub(crate) fn validate_embedding_batch(embeddings: &[Vec], expected: usize) -> Result<()> { - if embeddings.len() != expected { - anyhow::bail!( - "embedding backend returned {} vectors for {expected} inputs", - embeddings.len() - ); - } - let Some(size) = embeddings.first().map(Vec::len) else { - return Ok(()); - }; - if size == 0 { - anyhow::bail!("embedding backend returned an empty vector"); - } - if let Some((index, _)) = embeddings - .iter() - .enumerate() - .find(|(_, vector)| vector.len() != size) - { - anyhow::bail!("embedding backend returned inconsistent vector length at item {index}"); - } - Ok(()) -} - -pub(crate) fn validate_point_batch

(points: &[SemanticPoint

]) -> Result<()> { - let Some(vector_size) = points.first().map(|point| point.vector.len()) else { - return Ok(()); - }; - if vector_size == 0 { - anyhow::bail!("point 0 has an empty vector"); - } - let mut ids = HashSet::with_capacity(points.len()); - for (index, point) in points.iter().enumerate() { - if point.id.trim().is_empty() { - anyhow::bail!("point {index} has a blank id"); - } - if !ids.insert(point.id.as_str()) { - anyhow::bail!("point batch contains duplicate id {}", point.id); - } - if point.vector.len() != vector_size { - anyhow::bail!("point {index} has an inconsistent vector length"); - } - if point.vector.iter().any(|value| !value.is_finite()) { - anyhow::bail!("point {index} has a non-finite vector"); - } - } - Ok(()) -} - -fn validate_requested_point_ids(point_ids: &[String]) -> Result<()> { - if point_ids.is_empty() { - anyhow::bail!("exact Qdrant point retrieval requires at least one id"); - } - if point_ids.len() > QDRANT_POINT_BATCH_MAX { - anyhow::bail!( - "exact Qdrant point retrieval exceeds canonical maximum {QDRANT_POINT_BATCH_MAX}" - ); - } - let mut seen = HashSet::with_capacity(point_ids.len()); - for point_id in point_ids { - if point_id.trim().is_empty() { - anyhow::bail!("exact Qdrant point retrieval contains a blank requested id"); - } - if !seen.insert(point_id.as_str()) { - anyhow::bail!( - "exact Qdrant point retrieval contains duplicate requested id {point_id}" - ); - } - } - Ok(()) -} - -fn order_and_validate_retrieved_points

( - requested_ids: &[String], - returned: Vec>, -) -> Result>> { - validate_requested_point_ids(requested_ids)?; - let requested = requested_ids - .iter() - .map(String::as_str) - .collect::>(); - let mut by_id = HashMap::with_capacity(returned.len()); - for point in returned { - if !requested.contains(point.id.as_str()) { - anyhow::bail!( - "Qdrant substituted or returned unrequested point id {}", - point.id - ); - } - let payload = point - .payload - .context("Qdrant exact point response omitted a requested payload")?; - let vector = point - .vector - .context("Qdrant exact point response omitted a requested vector")?; - if vector.iter().any(|value| !value.is_finite()) { - anyhow::bail!("Qdrant exact point response contained a non-finite vector"); - } - let id = point.id; - if by_id - .insert( - id.clone(), - SemanticStoredPoint { - id: id.clone(), - payload: Some(payload), - vector: Some(vector), - }, - ) - .is_some() - { - anyhow::bail!("Qdrant exact point response duplicated point id {id}"); - } - } - if by_id.len() != requested_ids.len() { - let missing = requested_ids - .iter() - .find(|point_id| !by_id.contains_key(point_id.as_str())) - .expect("cardinality mismatch has a missing requested id"); - anyhow::bail!("Qdrant exact point response omitted requested point id {missing}"); - } - requested_ids - .iter() - .map(|point_id| { - by_id - .remove(point_id.as_str()) - .with_context(|| format!("Qdrant exact point response omitted {point_id}")) - }) - .collect() -} - -fn validate_completed_acknowledgement( - result: QdrantUpdateResult, -) -> Result { - if result.status != "completed" { - anyhow::bail!( - "Qdrant waited operation returned status {} instead of completed", - result.status - ); - } - Ok(QdrantCompletedAcknowledgement { - operation_id: result.operation_id, - }) -} - -#[derive(Deserialize)] -struct Envelope { - result: T, -} -#[derive(Deserialize)] -struct ExistsResult { - exists: bool, -} -#[derive(Deserialize)] -struct CollectionInfo { - config: CollectionConfig, -} -#[derive(Deserialize)] -struct CollectionConfig { - metadata: Option, -} -#[derive(Deserialize)] -struct QdrantUpdateResult { - operation_id: u64, - status: String, -} -#[derive(Deserialize)] -struct QueryResult

{ - points: Vec>, -} -#[derive(Deserialize)] -struct QueryPoint

{ - score: f32, - payload: Option

, -} -#[derive(Deserialize)] -struct ScrollResult { - points: Vec, - next_page_offset: Option, -} -#[derive(Deserialize)] -struct ScrollPoint { - id: String, -} -#[derive(Deserialize)] -struct PayloadScrollResult

{ - points: Vec>, - next_page_offset: Option, -} -#[derive(Deserialize)] -struct PayloadScrollPoint

{ - id: String, - payload: Option

, - vector: Option>, -} -#[derive(Deserialize)] -struct EmbedResponse { - embeddings: Option>>, -} - -#[derive(Deserialize)] -#[serde(deny_unknown_fields)] -struct OllamaTagsResponse { - models: Vec, -} - -#[derive(Deserialize)] -struct OllamaTag { - name: String, - model: String, - digest: String, -} - -fn normalize_ollama_digest(value: &str) -> Result { - let hex = value.strip_prefix("sha256:").unwrap_or(value); - if hex.len() != 64 || !hex.bytes().all(|byte| byte.is_ascii_hexdigit()) { - anyhow::bail!("Ollama model artifact digest is not a SHA-256 digest"); - } - Ok(format!("sha256:{}", hex.to_ascii_lowercase())) -} - -fn parse_response(response: Response) -> Result> { - let status = response.status(); - if !status.is_success() { - let body = response.text().unwrap_or_default(); - anyhow::bail!("Qdrant request failed with {status}: {body}"); - } - response - .json() - .context("failed to decode Qdrant response JSON") -} - -fn normalize_base_url(value: &str) -> String { - value.trim_end_matches('/').to_string() -} -fn timeout_seconds(timeout_ms: u64) -> u64 { - timeout_ms.div_ceil(1000).max(1) -} - -#[cfg(test)] -mod tests { - use super::*; - use wiremock::matchers::{body_json, method, path, query_param}; - use wiremock::{Mock, MockServer, ResponseTemplate}; - - fn embedder(base_url: String, model: &str) -> Result { - OllamaEmbedder::new(OllamaConfig { - base_url, - model: model.into(), - timeout_ms: 5_000, - query_instruction: String::new(), - }) - } - - fn qdrant(base_url: String) -> Result { - QdrantBackend::new(QdrantConfig { - url: base_url, - api_key: None, - timeout_ms: 5_000, - }) - } - - #[test] - fn waited_upsert_requires_completed_qdrant_acknowledgement() -> Result<()> { - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()?; - for (status, accepted) in [("completed", true), ("acknowledged", false)] { - let server = runtime.block_on(MockServer::start()); - runtime.block_on( - Mock::given(method("PUT")) - .and(path("/collections/c/points")) - .and(query_param("wait", "true")) - .and(query_param("timeout", "5")) - .and(body_json(json!({ - "points": [{"id":"p","vector":[1.0],"payload":{"kind":"test"}}] - }))) - .respond_with(ResponseTemplate::new(200).set_body_json(json!({ - "result": {"operation_id": 42, "status": status} - }))) - .mount(&server), - ); - let points = vec![SemanticPoint { - id: "p".into(), - vector: vec![1.0], - payload: json!({"kind":"test"}), - }]; - let result = qdrant(server.uri())?.upsert_point_batch_waited("c", &points); - assert_eq!(result.is_ok(), accepted); - if let Ok(acknowledgement) = result { - assert_eq!(acknowledgement.operation_id, 42); - } - } - Ok(()) - } - - #[test] - fn waited_upsert_enforces_one_canonical_batch() -> Result<()> { - let backend = qdrant("http://127.0.0.1:1".into())?; - let empty: Vec> = Vec::new(); - assert!(backend.upsert_point_batch_waited("c", &empty).is_err()); - let too_many = (0..=QDRANT_POINT_BATCH_MAX) - .map(|index| SemanticPoint { - id: index.to_string(), - vector: vec![1.0], - payload: Value::Null, - }) - .collect::>(); - assert!(backend.upsert_point_batch_waited("c", &too_many).is_err()); - Ok(()) - } - - #[test] - fn exact_point_retrieval_restores_request_order() -> Result<()> { - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()?; - let server = runtime.block_on(MockServer::start()); - runtime.block_on( - Mock::given(method("POST")) - .and(path("/collections/c/points")) - .and(query_param("timeout", "5")) - .and(body_json(json!({ - "ids": ["b", "a"], - "with_payload": true, - "with_vector": true - }))) - .respond_with(ResponseTemplate::new(200).set_body_json(json!({ - "result": [ - {"id":"a","payload":{"n":1},"vector":[1.0]}, - {"id":"b","payload":{"n":2},"vector":[2.0]} - ] - }))) - .mount(&server), - ); - let points = qdrant(server.uri())? - .retrieve_points_by_ids::("c", &["b".into(), "a".into()])?; - assert_eq!( - points - .iter() - .map(|point| point.id.as_str()) - .collect::>(), - vec!["b", "a"] - ); - Ok(()) - } - - #[test] - fn exact_point_response_validator_rejects_hostile_shapes() { - let requested = vec!["a".to_string(), "b".to_string()]; - let point = - |id: &str, payload: Option, vector: Option>| PayloadScrollPoint { - id: id.into(), - payload, - vector, - }; - assert!(validate_requested_point_ids(&[]).is_err()); - assert!(validate_requested_point_ids(&[" ".into()]).is_err()); - assert!(validate_requested_point_ids(&["a".into(), "a".into()]).is_err()); - assert!( - validate_requested_point_ids( - &(0..=QDRANT_POINT_BATCH_MAX) - .map(|index| index.to_string()) - .collect::>() - ) - .is_err() - ); - for returned in [ - vec![ - point("a", Some(json!({})), Some(vec![1.0])), - point("x", Some(json!({})), Some(vec![2.0])), - ], - vec![point("a", Some(json!({})), Some(vec![1.0]))], - vec![ - point("a", Some(json!({})), Some(vec![1.0])), - point("a", Some(json!({})), Some(vec![1.0])), - ], - vec![ - point("a", None, Some(vec![1.0])), - point("b", Some(json!({})), Some(vec![2.0])), - ], - vec![ - point("a", Some(json!({})), None), - point("b", Some(json!({})), Some(vec![2.0])), - ], - vec![ - point("a", Some(json!({})), Some(vec![f32::NAN])), - point("b", Some(json!({})), Some(vec![2.0])), - ], - ] { - assert!(order_and_validate_retrieved_points(&requested, returned).is_err()); - } - } - - #[test] - fn ollama_model_identity_is_bound_to_exact_installed_digest() -> Result<()> { - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()?; - let server_a = runtime.block_on(MockServer::start()); - let server_b = runtime.block_on(MockServer::start()); - for (server, digest) in [(&server_a, "aa".repeat(32)), (&server_b, "bb".repeat(32))] { - runtime.block_on( - Mock::given(method("GET")) - .and(path("/api/tags")) - .respond_with(ResponseTemplate::new(200).set_body_json(json!({ - "models": [{ - "name": "nomic-embed-text:latest", - "model": "nomic-embed-text:latest", - "digest": digest - }] - }))) - .mount(server), - ); - } - let identity_a = embedder(server_a.uri(), "nomic-embed-text:latest")? - .model_artifact()? - .canonical_identity(); - let identity_b = embedder(server_b.uri(), "nomic-embed-text:latest")? - .model_artifact()? - .canonical_identity(); - assert_ne!(identity_a, identity_b); - assert_eq!( - identity_a, - format!("nomic-embed-text:latest@sha256:{}", "aa".repeat(32)) - ); - Ok(()) - } - - #[test] - fn ollama_model_identity_refuses_absent_ambiguous_and_invalid_digest() -> Result<()> { - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()?; - for models in [ - json!([]), - json!([ - {"name":"m","model":"m","digest":"aa".repeat(32)}, - {"name":"m","model":"m","digest":"bb".repeat(32)} - ]), - json!([{"name":"m","model":"m","digest":"not-a-digest"}]), - ] { - let server = runtime.block_on(MockServer::start()); - runtime.block_on( - Mock::given(method("GET")) - .and(path("/api/tags")) - .respond_with( - ResponseTemplate::new(200).set_body_json(json!({"models": models})), - ) - .mount(&server), - ); - assert!(embedder(server.uri(), "m")?.model_artifact().is_err()); - } - Ok(()) - } -} diff --git a/epiphany-core/src/semantic_projector_service.rs b/epiphany-core/src/semantic_projector_service.rs deleted file mode 100644 index db6ca06e..00000000 --- a/epiphany-core/src/semantic_projector_service.rs +++ /dev/null @@ -1,293 +0,0 @@ -use crate::memory_graph::semantic_projector::{ - classify_memory_semantic_projection_for_pulse, execute_memory_semantic_projection, - idunn_acquire_memory_semantic_projection_with_config, - owned_running_memory_semantic_projection_claim, -}; -use crate::memory_graph::{ - MemorySemanticProjectorPulseClassification, MemorySemanticProjectorPulseOutcome, - MemorySemanticProjectorPulsePort, MemorySemanticProjectorPulser, -}; -use crate::{ - MemorySemanticIndexConfig, MemorySemanticProjectionInput, - runtime_modeling_semantic_projection_input, -}; -use anyhow::{Result, anyhow}; -use chrono::{SecondsFormat, Utc}; -use sha2::{Digest, Sha256}; -#[cfg(windows)] -use std::ffi::OsStr; -#[cfg(unix)] -use std::fs::File; -#[cfg(unix)] -use std::os::fd::AsRawFd; -#[cfg(windows)] -use std::os::windows::ffi::OsStrExt; -use std::path::{Path, PathBuf}; -use uuid::Uuid; - -#[cfg(windows)] -use windows_sys::Win32::Foundation::{CloseHandle, ERROR_ALREADY_EXISTS, GetLastError, HANDLE}; -#[cfg(windows)] -use windows_sys::Win32::System::Threading::{CreateMutexW, ReleaseMutex}; - -/// Trusted in-process authority held by the one Idunn-managed projector body. -/// The constructor generates process-stable incarnations; callers cannot label -/// themselves as an existing Idunn or executor incarnation. -const SEMANTIC_PROJECTOR_EXECUTOR_ID: &str = "epiphany-memory-semantic-projector"; - -struct LocalIdunnSemanticProjectorSession { - modeling_store: PathBuf, - executor_id: String, - executor_incarnation: String, - idunn_incarnation: String, - config: MemorySemanticIndexConfig, -} - -struct SemanticProjectorSingletonGuard { - #[cfg(windows)] - handle: HANDLE, - #[cfg(unix)] - file: File, -} - -impl Drop for SemanticProjectorSingletonGuard { - fn drop(&mut self) { - #[cfg(windows)] - unsafe { - let _ = ReleaseMutex(self.handle); - CloseHandle(self.handle); - } - #[cfg(unix)] - unsafe { - let _ = libc::flock(self.file.as_raw_fd(), libc::LOCK_UN); - } - } -} - -fn acquire_semantic_projector_singleton( - modeling_store: impl AsRef, -) -> Result { - let modeling = canonical_file(&modeling_store, "Modeling")?; - let identity = format!( - "{:x}", - Sha256::digest(modeling.to_string_lossy().to_lowercase().as_bytes()) - ); - #[cfg(windows)] - { - let name = OsStr::new(&format!("Global\\EpiphanySemanticProjector-{identity}")) - .encode_wide() - .chain(std::iter::once(0)) - .collect::>(); - let handle = unsafe { CreateMutexW(std::ptr::null_mut(), 1, name.as_ptr()) }; - if handle.is_null() { - return Err(anyhow!( - "semantic projector singleton mutex creation failed: {}", - unsafe { GetLastError() } - )); - } - if unsafe { GetLastError() } == ERROR_ALREADY_EXISTS { - unsafe { CloseHandle(handle) }; - return Err(anyhow!( - "semantic projector owner already exists for canonical store pair" - )); - } - return Ok(SemanticProjectorSingletonGuard { handle }); - } - #[cfg(unix)] - { - let path = std::env::temp_dir().join(format!("epiphany-semantic-{identity}.lock")); - let file = File::options() - .create(true) - .read(true) - .write(true) - .open(path)?; - if unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) } != 0 { - return Err(anyhow!( - "semantic projector owner already exists for canonical store pair" - )); - } - return Ok(SemanticProjectorSingletonGuard { file }); - } - #[allow(unreachable_code)] - Err(anyhow!( - "semantic projector singleton is unsupported on this platform" - )) -} - -impl LocalIdunnSemanticProjectorSession { - fn new( - modeling_store: impl AsRef, - executor_id: impl Into, - config: MemorySemanticIndexConfig, - ) -> Result { - let modeling_store = canonical_file(&modeling_store, "Modeling")?; - let executor_id = executor_id.into(); - if executor_id.trim().is_empty() { - return Err(anyhow!("semantic projector executor id must not be empty")); - } - Ok(Self { - modeling_store, - executor_id, - executor_incarnation: format!("projector-{}", Uuid::new_v4()), - idunn_incarnation: format!("idunn-{}", Uuid::new_v4()), - config, - }) - } - - pub fn provider_incarnation(&self) -> &str { - &self.executor_incarnation - } - - fn store_for(&self, input: &MemorySemanticProjectionInput) -> Result<&Path> { - match input.obligation().partition.as_str() { - "modeling" => Ok(&self.modeling_store), - other => Err(anyhow!( - "unsupported semantic projector partition {other:?}" - )), - } - } -} - -/// The only public authority-bearing semantic projector body. Construction -/// atomically takes the host-wide singleton before minting a process session, -/// and the guard remains owned for the body's full lifetime. -pub struct SemanticProjectorServiceBody { - _singleton: SemanticProjectorSingletonGuard, - pulser: MemorySemanticProjectorPulser, - provider_incarnation: String, -} - -pub struct SemanticProjectorServicePulse { - pub outcome: MemorySemanticProjectorPulseOutcome, - pub inputs: Vec, - pub source_fault_count: u32, -} - -impl SemanticProjectorServiceBody { - pub fn new( - modeling_store: impl AsRef, - config: MemorySemanticIndexConfig, - ) -> Result { - let singleton = acquire_semantic_projector_singleton(&modeling_store)?; - let session = LocalIdunnSemanticProjectorSession::new( - modeling_store, - SEMANTIC_PROJECTOR_EXECUTOR_ID, - config, - )?; - let provider_incarnation = session.provider_incarnation().to_string(); - Ok(Self { - _singleton: singleton, - pulser: MemorySemanticProjectorPulser::new(session), - provider_incarnation, - }) - } - - pub fn provider_incarnation(&self) -> &str { - &self.provider_incarnation - } - - pub fn pulse(&self) -> SemanticProjectorServicePulse { - let session = &self.pulser.port; - let (inputs, source_fault_count) = - match runtime_modeling_semantic_projection_input(&session.modeling_store) { - Ok(input) => (vec![input], 0), - Err(_) => (Vec::new(), 1), - }; - let outcome = inputs.first().map_or_else( - || MemorySemanticProjectorPulseOutcome { - status: crate::MemorySemanticProjectorPulseStatus::Idle, - selected_scope_id: None, - inspections: Vec::new(), - error: None, - }, - |input| self.pulser.pulse(input), - ); - SemanticProjectorServicePulse { - outcome, - inputs, - source_fault_count, - } - } -} - -impl MemorySemanticProjectorPulsePort for LocalIdunnSemanticProjectorSession { - fn classify( - &self, - input: &MemorySemanticProjectionInput, - ) -> Result { - let store = self.store_for(input)?; - let classification = classify_memory_semantic_projection_for_pulse(store, input)?; - if classification == MemorySemanticProjectorPulseClassification::Running { - if let Some(claim_id) = owned_running_memory_semantic_projection_claim( - store, - input, - &self.executor_id, - &self.executor_incarnation, - )? { - return Ok(MemorySemanticProjectorPulseClassification::RunningOwned { claim_id }); - } - } - Ok(classification) - } - - fn acquire( - &self, - input: &MemorySemanticProjectionInput, - purpose: &str, - ) -> Result> { - let store = self.store_for(input)?; - match idunn_acquire_memory_semantic_projection_with_config( - store, - input, - &self.executor_id, - &self.executor_incarnation, - purpose, - &self.idunn_incarnation, - &Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true), - &self.config, - ) { - Ok(acquisition) => Ok(Some(acquisition.claim.claim_id)), - Err(_error) - if classify_memory_semantic_projection_for_pulse(store, input)? - == MemorySemanticProjectorPulseClassification::Running => - { - Ok(None) - } - Err(error) => Err(error), - } - } - - fn execute(&self, input: &MemorySemanticProjectionInput, claim_id: &str) -> Result<()> { - execute_memory_semantic_projection(self.store_for(input)?, input, claim_id, &self.config)?; - Ok(()) - } -} - -fn canonical_file(path: &impl AsRef, label: &str) -> Result { - let path = path.as_ref(); - if !path.is_file() { - return Err(anyhow!( - "{label} canonical store is missing: {}", - path.display() - )); - } - path.canonicalize() - .map_err(|error| anyhow!("{label} canonical store identity is unavailable: {error}")) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn singleton_refuses_a_second_process_owner_identity() -> Result<()> { - let temp = tempfile::tempdir()?; - let modeling = temp.path().join("modeling.ccmp"); - std::fs::write(&modeling, [])?; - let first = acquire_semantic_projector_singleton(&modeling)?; - assert!(acquire_semantic_projector_singleton(&modeling).is_err()); - drop(first); - assert!(acquire_semantic_projector_singleton(&modeling).is_ok()); - Ok(()) - } -} diff --git a/epiphany-core/src/workspace_coverage_process_bootstrap.rs b/epiphany-core/src/workspace_coverage_process_bootstrap.rs deleted file mode 100644 index b6bb15db..00000000 --- a/epiphany-core/src/workspace_coverage_process_bootstrap.rs +++ /dev/null @@ -1,91 +0,0 @@ -use anyhow::{Context, Result, anyhow, bail}; -use std::io::{Read, Write}; -use uuid::Uuid; -use zeroize::Zeroize; - -const MAGIC: &[u8; 8] = b"EPHWCOV\0"; -const FRAME_LEN: usize = MAGIC.len() + 16 + 32; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageProcessBootstrap { - pub launch_id: Uuid, - pub provider_signing_seed: [u8; 32], -} - -impl Drop for WorkspaceCoverageProcessBootstrap { - fn drop(&mut self) { - self.provider_signing_seed.zeroize(); - } -} - -pub fn write_workspace_coverage_process_bootstrap( - mut writer: impl Write, - frame: &WorkspaceCoverageProcessBootstrap, -) -> Result<()> { - let mut bytes = [0_u8; FRAME_LEN]; - bytes[..MAGIC.len()].copy_from_slice(MAGIC); - bytes[MAGIC.len()..MAGIC.len() + 16].copy_from_slice(frame.launch_id.as_bytes()); - bytes[MAGIC.len() + 16..].copy_from_slice(&frame.provider_signing_seed); - writer - .write_all(&bytes) - .context("failed to write workspace coverage bootstrap frame")?; - writer - .flush() - .context("failed to flush workspace coverage bootstrap frame") -} - -pub fn read_workspace_coverage_process_bootstrap( - mut reader: impl Read, -) -> Result { - let mut bytes = [0_u8; FRAME_LEN]; - reader - .read_exact(&mut bytes) - .context("workspace coverage bootstrap frame is truncated")?; - let mut trailing = [0_u8; 1]; - if reader - .read(&mut trailing) - .context("failed to verify workspace coverage bootstrap EOF")? - != 0 - { - bail!("workspace coverage bootstrap contains trailing bytes"); - } - if &bytes[..MAGIC.len()] != MAGIC { - bail!("workspace coverage bootstrap magic is invalid"); - } - let launch_id = Uuid::from_slice(&bytes[MAGIC.len()..MAGIC.len() + 16]) - .map_err(|_| anyhow!("workspace coverage bootstrap launch id is invalid"))?; - let provider_signing_seed = bytes[MAGIC.len() + 16..] - .try_into() - .map_err(|_| anyhow!("workspace coverage bootstrap seed length is invalid"))?; - Ok(WorkspaceCoverageProcessBootstrap { - launch_id, - provider_signing_seed, - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn fixed_frame_round_trips_and_requires_eof() { - let frame = WorkspaceCoverageProcessBootstrap { - launch_id: Uuid::new_v4(), - provider_signing_seed: [7; 32], - }; - let mut encoded = Vec::new(); - write_workspace_coverage_process_bootstrap(&mut encoded, &frame).unwrap(); - assert_eq!(encoded.len(), FRAME_LEN); - assert_eq!( - read_workspace_coverage_process_bootstrap(encoded.as_slice()).unwrap(), - frame - ); - encoded.push(0); - assert!(read_workspace_coverage_process_bootstrap(encoded.as_slice()).is_err()); - } - - #[test] - fn truncated_frame_is_rejected() { - assert!(read_workspace_coverage_process_bootstrap(&[0_u8; FRAME_LEN - 1][..]).is_err()); - } -} diff --git a/epiphany-core/src/workspace_coverage_process_documents.rs b/epiphany-core/src/workspace_coverage_process_documents.rs deleted file mode 100644 index d2608cad..00000000 --- a/epiphany-core/src/workspace_coverage_process_documents.rs +++ /dev/null @@ -1,4889 +0,0 @@ -use crate::cultmesh_integration::validate_workspace_coverage_projector_managed_service_policy; -use crate::{ - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID, EpiphanyCultMeshManagedServicePolicyEntry, - HOST_IDENTITY_KEY, HOST_IDENTITY_TYPE, HostIdentitySignature, HostIdentitySigner, - HostIncarnationIdentityEntry, ProcessInstanceIdentity, ProcessInstanceObservation, - native_boot_identity, observe_process_instance, open_epiphany_cultmesh_node, - verify_host_identity_signature, -}; -use anyhow::{Context, Result, anyhow, bail}; -use chrono::DateTime; -use cultcache_rs::{ - CacheBackingStore, CultCacheEnvelope, DatabaseEntry, SingleFileMessagePackBackingStore, -}; -use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; -use serde::Serialize; -use sha2::{Digest, Sha256}; -use std::path::Path; - -pub const WORKSPACE_COVERAGE_PROCESS_LAUNCH_TYPE: &str = - "epiphany.workspace_coverage.managed_process_launch"; -pub const WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.managed_process_launch.v1"; -pub const WORKSPACE_COVERAGE_PROCESS_LAUNCH_LATEST_KEY: &str = - "epiphany-local/workspace-coverage/managed-process-launch/latest"; -pub const WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_TYPE: &str = - "epiphany.workspace_coverage.provider_heartbeat"; -pub const WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.provider_heartbeat.v0"; -pub const WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_LATEST_KEY: &str = - "epiphany-local/workspace-coverage/provider-heartbeat/latest/"; -pub const WORKSPACE_COVERAGE_PROCESS_TERMINATION_TYPE: &str = - "epiphany.workspace_coverage.process_termination_observation"; -pub const WORKSPACE_COVERAGE_PROCESS_TERMINATION_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.process_termination_observation.v1"; -pub(crate) const WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.process_evidence_head.v0"; - -const HOST_LAUNCH_PURPOSE: &str = "epiphany.workspace-coverage.managed-process-launch.v0"; -const PROVIDER_HEARTBEAT_DOMAIN: &[u8] = - b"epiphany.workspace-coverage.provider-heartbeat.signature.v0\0"; -const HOST_TERMINATION_PURPOSE: &str = - "epiphany.workspace-coverage.process-termination-observation.v0"; -const WORKSPACE_COVERAGE_TERMINATION_OBSERVER: &str = "epiphany-daemon-supervisor"; -const COVERAGE_ADVANCEMENT_SIGHT_DOMAIN: &[u8] = - b"epiphany.workspace-coverage.advancement-sight.signature.v0\0"; -const COVERAGE_TERMINAL_SIGHT_DOMAIN: &[u8] = - b"epiphany.workspace-coverage.terminal-sight.signature.v0\0"; -const COVERAGE_CLAIM_SIGHT_DOMAIN: &[u8] = - b"epiphany.workspace-coverage.claim-sight.signature.v0\0"; -const HOST_RECOVERY_DIRECTIVE_PURPOSE: &str = - "epiphany.workspace-coverage.host-recovery-directive.v0"; - -pub const WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_TYPE: &str = - "epiphany.workspace_coverage.advancement_sight"; -pub const WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.advancement_sight.v0"; -pub const WORKSPACE_COVERAGE_TERMINAL_SIGHT_TYPE: &str = - "epiphany.workspace_coverage.terminal_sight"; -pub const WORKSPACE_COVERAGE_TERMINAL_SIGHT_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.terminal_sight.v0"; -pub const WORKSPACE_COVERAGE_CLAIM_SIGHT_TYPE: &str = "epiphany.workspace_coverage.claim_sight"; -pub const WORKSPACE_COVERAGE_CLAIM_SIGHT_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.claim_sight.v0"; -pub const WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_TYPE: &str = - "epiphany.workspace_coverage.recovery_directive"; -pub const WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.recovery_directive.v0"; - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.claim_sight", - schema = "WorkspaceCoverageClaimSightEntry" -)] -pub struct WorkspaceCoverageClaimSightEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub runtime_id: String, - #[cultcache(key = 2)] - pub workspace_id: String, - #[cultcache(key = 3)] - pub launch_id: String, - #[cultcache(key = 4)] - pub launch_envelope_digest: String, - #[cultcache(key = 5)] - pub provider_incarnation_id: String, - #[cultcache(key = 6)] - pub provider_public_key: Vec, - #[cultcache(key = 7)] - pub coverage_store_binding_id: String, - #[cultcache(key = 8)] - pub coverage_store_binding_envelope_digest: String, - #[cultcache(key = 9)] - pub coverage_store_file_identity: String, - #[cultcache(key = 10)] - pub runtime_coverage_route_envelope_digest: String, - #[cultcache(key = 11)] - pub body_binding_sha256: String, - #[cultcache(key = 12)] - pub body_observation_id: String, - #[cultcache(key = 13)] - pub body_generation: u64, - #[cultcache(key = 14)] - pub manifest_root_sha256: String, - #[cultcache(key = 15)] - pub claim_id: String, - #[cultcache(key = 16)] - pub claim_epoch: u64, - #[cultcache(key = 17)] - pub plan_id: String, - #[cultcache(key = 18)] - pub attempt_id: String, - #[cultcache(key = 19)] - pub attempt_envelope_digest: String, - #[cultcache(key = 20)] - pub recovery_receipt_id: Option, - #[cultcache(key = 21)] - pub recovery_receipt_digest: Option, - #[cultcache(key = 22)] - pub observed_at_utc: String, - #[cultcache(key = 23)] - pub provider_signature: Vec, - #[cultcache(key = 24)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.recovery_directive", - schema = "WorkspaceCoverageRecoveryDirectiveEntry" -)] -pub struct WorkspaceCoverageRecoveryDirectiveEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub directive_id: String, - #[cultcache(key = 2)] - pub runtime_id: String, - #[cultcache(key = 3)] - pub old_claim_id: String, - #[cultcache(key = 4)] - pub old_launch_id: String, - #[cultcache(key = 5)] - pub replacement_launch_id: String, - #[cultcache(key = 6)] - pub replacement_ready_heartbeat_id: String, - #[cultcache(key = 7)] - pub termination_id: String, - #[cultcache(key = 8)] - pub claim_sight_envelope_digest: String, - #[cultcache(key = 9)] - pub old_claim_epoch: u64, - #[cultcache(key = 10)] - pub old_plan_id: String, - #[cultcache(key = 11)] - pub termination_envelope_digest: String, - #[cultcache(key = 12)] - pub replacement_launch_envelope_digest: String, - #[cultcache(key = 13)] - pub replacement_ready_heartbeat_envelope_digest: String, - #[cultcache(key = 14)] - pub workspace_id: String, - #[cultcache(key = 15)] - pub body_binding_sha256: String, - #[cultcache(key = 16)] - pub body_observation_id: String, - #[cultcache(key = 17)] - pub body_generation: u64, - #[cultcache(key = 18)] - pub manifest_root_sha256: String, - #[cultcache(key = 19)] - pub coverage_store_binding_id: String, - #[cultcache(key = 20)] - pub coverage_store_binding_envelope_digest: String, - #[cultcache(key = 21)] - pub coverage_store_file_identity: String, - #[cultcache(key = 22)] - pub runtime_coverage_route_envelope_digest: String, - #[cultcache(key = 23)] - pub issued_at_utc: String, - #[cultcache(key = 24)] - pub host_identity_id: String, - #[cultcache(key = 25)] - pub host_identity_record_digest: String, - #[cultcache(key = 26)] - pub host_signature: Vec, - #[cultcache(key = 27)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.advancement_sight", - schema = "WorkspaceCoverageAdvancementSightEntry" -)] -pub struct WorkspaceCoverageAdvancementSightEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub runtime_id: String, - #[cultcache(key = 2)] - pub workspace_id: String, - #[cultcache(key = 3)] - pub launch_id: String, - #[cultcache(key = 4)] - pub launch_envelope_digest: String, - #[cultcache(key = 5)] - pub provider_incarnation_id: String, - #[cultcache(key = 6)] - pub provider_public_key: Vec, - #[cultcache(key = 7)] - pub coverage_store_binding_id: String, - #[cultcache(key = 8)] - pub coverage_store_binding_envelope_digest: String, - #[cultcache(key = 9)] - pub coverage_store_file_identity: String, - #[cultcache(key = 10)] - pub runtime_coverage_route_envelope_digest: String, - #[cultcache(key = 11)] - pub body_binding_sha256: String, - #[cultcache(key = 12)] - pub body_observation_id: String, - #[cultcache(key = 13)] - pub body_generation: u64, - #[cultcache(key = 14)] - pub manifest_root_sha256: String, - #[cultcache(key = 15)] - pub claim_id: String, - #[cultcache(key = 16)] - pub claim_epoch: u64, - #[cultcache(key = 17)] - pub plan_id: String, - #[cultcache(key = 18)] - pub progress_id: String, - #[cultcache(key = 19)] - pub progress_envelope_digest: String, - #[cultcache(key = 20)] - pub checkpoint_id: String, - #[cultcache(key = 21)] - pub checkpoint_envelope_digest: String, - #[cultcache(key = 22)] - pub sequence: u64, - #[cultcache(key = 23)] - pub status: String, - #[cultcache(key = 24)] - pub completed_units: u64, - #[cultcache(key = 25)] - pub total_units: u64, - #[cultcache(key = 26)] - pub last_advanced_at_utc: String, - #[cultcache(key = 27)] - pub observed_at_utc: String, - #[cultcache(key = 28)] - pub provider_signature: Vec, - #[cultcache(key = 29)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.terminal_sight", - schema = "WorkspaceCoverageTerminalSightEntry" -)] -pub struct WorkspaceCoverageTerminalSightEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub runtime_id: String, - #[cultcache(key = 2)] - pub workspace_id: String, - #[cultcache(key = 3)] - pub launch_id: String, - #[cultcache(key = 4)] - pub launch_envelope_digest: String, - #[cultcache(key = 5)] - pub provider_incarnation_id: String, - #[cultcache(key = 6)] - pub provider_public_key: Vec, - #[cultcache(key = 7)] - pub coverage_store_binding_id: String, - #[cultcache(key = 8)] - pub coverage_store_binding_envelope_digest: String, - #[cultcache(key = 9)] - pub coverage_store_file_identity: String, - #[cultcache(key = 10)] - pub runtime_coverage_route_envelope_digest: String, - #[cultcache(key = 11)] - pub body_binding_sha256: String, - #[cultcache(key = 12)] - pub body_observation_id: String, - #[cultcache(key = 13)] - pub body_generation: u64, - #[cultcache(key = 14)] - pub manifest_root_sha256: String, - #[cultcache(key = 15)] - pub claim_id: String, - #[cultcache(key = 16)] - pub claim_epoch: u64, - #[cultcache(key = 17)] - pub plan_id: String, - #[cultcache(key = 18)] - pub receipt_id: String, - #[cultcache(key = 19)] - pub receipt_envelope_digest: String, - #[cultcache(key = 20)] - pub head_id: String, - #[cultcache(key = 21)] - pub head_envelope_digest: String, - #[cultcache(key = 22)] - pub sequence: u64, - #[cultcache(key = 23)] - pub status: String, - #[cultcache(key = 24)] - pub observed_at_utc: String, - #[cultcache(key = 25)] - pub provider_signature: Vec, - #[cultcache(key = 26)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.managed_process_launch", - schema = "WorkspaceCoverageManagedProcessLaunchEntry" -)] -pub struct WorkspaceCoverageManagedProcessLaunchEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub launch_id: String, - #[cultcache(key = 2)] - pub service_id: String, - #[cultcache(key = 3)] - pub provider_daemon_id: String, - #[cultcache(key = 4)] - pub runtime_id: String, - #[cultcache(key = 5)] - pub policy_id: String, - #[cultcache(key = 6)] - pub policy_envelope_digest: String, - #[cultcache(key = 7)] - pub command: String, - #[cultcache(key = 8)] - pub args: Vec, - #[cultcache(key = 9)] - pub cwd: Option, - #[cultcache(key = 10)] - pub launched_at_utc: String, - #[cultcache(key = 11)] - pub host_identity_id: String, - #[cultcache(key = 12)] - pub host_public_key: Vec, - #[cultcache(key = 13)] - pub host_assurance: String, - #[cultcache(key = 14)] - pub host_identity_record_digest: String, - #[cultcache(key = 15)] - pub boot_identity: String, - #[cultcache(key = 16)] - pub process_id: u32, - #[cultcache(key = 17)] - pub process_creation_token: u64, - #[cultcache(key = 18)] - pub process_created_at_rfc3339: Option, - #[cultcache(key = 19)] - pub process_executable_path: String, - #[cultcache(key = 20)] - pub executable_sha256: String, - #[cultcache(key = 21)] - pub provider_incarnation_id: String, - #[cultcache(key = 22)] - pub provider_public_key: Vec, - #[cultcache(key = 23)] - pub host_signature: Vec, - #[cultcache(key = 24)] - pub supervisor_id: String, - #[cultcache(key = 25)] - pub identity_captured_at_utc: String, - #[cultcache(key = 26)] - pub signature_algorithm: String, - #[cultcache(key = 27, default)] - pub replaces_launch_id: Option, - #[cultcache(key = 28, default)] - pub replaces_termination_id: Option, - #[cultcache(key = 29, default)] - pub replaces_termination_envelope_digest: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.provider_heartbeat", - schema = "WorkspaceCoverageProviderHeartbeatEntry" -)] -pub struct WorkspaceCoverageProviderHeartbeatEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub heartbeat_id: String, - #[cultcache(key = 2)] - pub launch_id: String, - #[cultcache(key = 3)] - pub launch_envelope_digest: String, - #[cultcache(key = 4)] - pub service_id: String, - #[cultcache(key = 5)] - pub provider_daemon_id: String, - #[cultcache(key = 6)] - pub runtime_id: String, - #[cultcache(key = 7)] - pub host_identity_id: String, - #[cultcache(key = 8)] - pub host_identity_record_digest: String, - #[cultcache(key = 9)] - pub boot_identity: String, - #[cultcache(key = 10)] - pub process_id: u32, - #[cultcache(key = 11)] - pub process_creation_token: u64, - #[cultcache(key = 12)] - pub process_executable_path: String, - #[cultcache(key = 13)] - pub provider_incarnation_id: String, - #[cultcache(key = 14)] - pub provider_public_key: Vec, - #[cultcache(key = 15)] - pub sequence: u64, - #[cultcache(key = 16)] - pub status: String, - #[cultcache(key = 17)] - pub observed_at_utc: String, - #[cultcache(key = 18)] - pub provider_signature: Vec, - #[cultcache(key = 19)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.process_termination_observation", - schema = "WorkspaceCoverageProcessTerminationObservationEntry" -)] -pub struct WorkspaceCoverageProcessTerminationObservationEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub termination_id: String, - #[cultcache(key = 2)] - pub launch_id: String, - #[cultcache(key = 3)] - pub launch_envelope_digest: String, - #[cultcache(key = 4)] - pub heartbeat_id: Option, - #[cultcache(key = 5, default)] - pub heartbeat_envelope_digest: Option, - #[cultcache(key = 6)] - pub policy_id: String, - #[cultcache(key = 7)] - pub policy_envelope_digest: String, - #[cultcache(key = 8)] - pub runtime_id: String, - #[cultcache(key = 9)] - pub host_identity_id: String, - #[cultcache(key = 10)] - pub host_identity_record_digest: String, - #[cultcache(key = 11)] - pub expected_boot_identity: String, - #[cultcache(key = 12)] - pub expected_process_id: u32, - #[cultcache(key = 13)] - pub expected_process_creation_token: u64, - #[cultcache(key = 14)] - pub expected_process_executable_path: String, - #[cultcache(key = 15)] - pub observed_boot_identity: String, - #[cultcache(key = 16)] - pub outcome: String, - #[cultcache(key = 17)] - pub exit_code: Option, - #[cultcache(key = 18)] - pub replacement_process_id: Option, - #[cultcache(key = 19)] - pub replacement_process_creation_token: Option, - #[cultcache(key = 20)] - pub replacement_process_created_at_rfc3339: Option, - #[cultcache(key = 21)] - pub replacement_process_executable_path: Option, - #[cultcache(key = 22)] - pub observed_at_utc: String, - #[cultcache(key = 23)] - pub observer_id: String, - #[cultcache(key = 24)] - pub host_signature: Vec, - #[cultcache(key = 25)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.process_evidence_head", - schema = "WorkspaceCoverageProcessEvidenceHead" -)] -pub(crate) struct WorkspaceCoverageProcessEvidenceHead { - #[cultcache(key = 0)] - schema_version: String, - #[cultcache(key = 1)] - launch_id: String, - #[cultcache(key = 2)] - generation: u64, - #[cultcache(key = 3)] - state: String, - #[cultcache(key = 4, default)] - heartbeat_id: Option, - #[cultcache(key = 5, default)] - termination_id: Option, -} - -trait WorkspaceCoverageProcessObservationSource { - fn boot_identity(&self) -> Option; - fn observe(&self, expected: &ProcessInstanceIdentity) -> ProcessInstanceObservation; -} - -struct NativeWorkspaceCoverageProcessObservationSource; -impl WorkspaceCoverageProcessObservationSource for NativeWorkspaceCoverageProcessObservationSource { - fn boot_identity(&self) -> Option { - native_boot_identity() - } - fn observe(&self, expected: &ProcessInstanceIdentity) -> ProcessInstanceObservation { - observe_process_instance(expected) - } -} - -/// A typed, non-mutating observation of the exact process incarnation named by -/// a workspace-coverage launch. Reconciliation must branch on this value; -/// errors and uncertain observations are never evidence of termination. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum WorkspaceCoverageProcessLifecycleObservation { - ExactAlive, - BootSuperseded { observed_boot_identity: String }, - ExactExited { exit_code: Option }, - Missing, - Replaced { observed: ProcessInstanceIdentity }, - Inaccessible, - Indeterminate { reason: String }, -} - -fn observe_workspace_coverage_process_with_source( - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - source: &dyn WorkspaceCoverageProcessObservationSource, -) -> WorkspaceCoverageProcessLifecycleObservation { - let Some(observed_boot_identity) = source.boot_identity() else { - return WorkspaceCoverageProcessLifecycleObservation::Indeterminate { - reason: "current boot identity is unavailable".to_string(), - }; - }; - if observed_boot_identity != launch.boot_identity { - return WorkspaceCoverageProcessLifecycleObservation::BootSuperseded { - observed_boot_identity, - }; - } - match source.observe(&process_identity_from_workspace_coverage_launch(launch)) { - ProcessInstanceObservation::ExactAlive => { - WorkspaceCoverageProcessLifecycleObservation::ExactAlive - } - ProcessInstanceObservation::ExactExited { exit_code } => { - WorkspaceCoverageProcessLifecycleObservation::ExactExited { exit_code } - } - ProcessInstanceObservation::Missing => { - WorkspaceCoverageProcessLifecycleObservation::Missing - } - ProcessInstanceObservation::Replaced { observed } => { - WorkspaceCoverageProcessLifecycleObservation::Replaced { observed } - } - ProcessInstanceObservation::Inaccessible => { - WorkspaceCoverageProcessLifecycleObservation::Inaccessible - } - ProcessInstanceObservation::Indeterminate { reason } => { - WorkspaceCoverageProcessLifecycleObservation::Indeterminate { reason } - } - } -} - -#[derive(Serialize)] -struct LaunchStatement<'a> { - schema_version: &'a str, - launch_id: &'a str, - service_id: &'a str, - provider_daemon_id: &'a str, - runtime_id: &'a str, - policy_id: &'a str, - policy_envelope_digest: &'a str, - command: &'a str, - args: &'a [String], - cwd: &'a Option, - launched_at_utc: &'a str, - host_identity_id: &'a str, - host_public_key: &'a [u8], - host_assurance: &'a str, - host_identity_record_digest: &'a str, - boot_identity: &'a str, - process_id: u32, - process_creation_token: u64, - process_created_at_rfc3339: &'a Option, - process_executable_path: &'a str, - executable_sha256: &'a str, - provider_incarnation_id: &'a str, - provider_public_key: &'a [u8], - supervisor_id: &'a str, - identity_captured_at_utc: &'a str, - signature_algorithm: &'a str, - replaces_launch_id: &'a Option, - replaces_termination_id: &'a Option, - replaces_termination_envelope_digest: &'a Option, -} - -#[derive(Serialize)] -struct HeartbeatStatement<'a> { - schema_version: &'a str, - heartbeat_id: &'a str, - launch_id: &'a str, - launch_envelope_digest: &'a str, - service_id: &'a str, - provider_daemon_id: &'a str, - runtime_id: &'a str, - host_identity_id: &'a str, - host_identity_record_digest: &'a str, - boot_identity: &'a str, - process_id: u32, - process_creation_token: u64, - process_executable_path: &'a str, - provider_incarnation_id: &'a str, - provider_public_key: &'a [u8], - sequence: u64, - status: &'a str, - observed_at_utc: &'a str, - signature_algorithm: &'a str, -} - -#[derive(Serialize)] -struct TerminationStatement<'a> { - schema_version: &'a str, - termination_id: &'a str, - launch_id: &'a str, - launch_envelope_digest: &'a str, - heartbeat_id: &'a Option, - heartbeat_envelope_digest: &'a Option, - policy_id: &'a str, - policy_envelope_digest: &'a str, - runtime_id: &'a str, - host_identity_id: &'a str, - host_identity_record_digest: &'a str, - expected_boot_identity: &'a str, - expected_process_id: u32, - expected_process_creation_token: u64, - expected_process_executable_path: &'a str, - observed_boot_identity: &'a str, - outcome: &'a str, - exit_code: Option, - replacement_process_id: Option, - replacement_process_creation_token: Option, - replacement_process_created_at_rfc3339: &'a Option, - replacement_process_executable_path: &'a Option, - observed_at_utc: &'a str, - observer_id: &'a str, - signature_algorithm: &'a str, -} - -pub fn workspace_coverage_host_identity_record_digest( - entry: &HostIncarnationIdentityEntry, -) -> Result { - let payload = rmp_serde::to_vec(entry)?; - let mut digest = Sha256::new(); - digest.update(HOST_IDENTITY_TYPE.as_bytes()); - digest.update([0]); - digest.update(HOST_IDENTITY_KEY.as_bytes()); - digest.update([0]); - digest.update(payload); - Ok(format!("sha256-{:x}", digest.finalize())) -} - -pub fn workspace_coverage_launch_statement( - entry: &WorkspaceCoverageManagedProcessLaunchEntry, -) -> Result> { - Ok(rmp_serde::to_vec_named(&LaunchStatement { - schema_version: &entry.schema_version, - launch_id: &entry.launch_id, - service_id: &entry.service_id, - provider_daemon_id: &entry.provider_daemon_id, - runtime_id: &entry.runtime_id, - policy_id: &entry.policy_id, - policy_envelope_digest: &entry.policy_envelope_digest, - command: &entry.command, - args: &entry.args, - cwd: &entry.cwd, - launched_at_utc: &entry.launched_at_utc, - host_identity_id: &entry.host_identity_id, - host_public_key: &entry.host_public_key, - host_assurance: &entry.host_assurance, - host_identity_record_digest: &entry.host_identity_record_digest, - boot_identity: &entry.boot_identity, - process_id: entry.process_id, - process_creation_token: entry.process_creation_token, - process_created_at_rfc3339: &entry.process_created_at_rfc3339, - process_executable_path: &entry.process_executable_path, - executable_sha256: &entry.executable_sha256, - provider_incarnation_id: &entry.provider_incarnation_id, - provider_public_key: &entry.provider_public_key, - supervisor_id: &entry.supervisor_id, - identity_captured_at_utc: &entry.identity_captured_at_utc, - signature_algorithm: &entry.signature_algorithm, - replaces_launch_id: &entry.replaces_launch_id, - replaces_termination_id: &entry.replaces_termination_id, - replaces_termination_envelope_digest: &entry.replaces_termination_envelope_digest, - })?) -} - -pub fn sign_workspace_coverage_launch( - entry: &mut WorkspaceCoverageManagedProcessLaunchEntry, - signer: &HostIdentitySigner, -) -> Result<()> { - entry.host_signature.clear(); - let proof = signer.sign( - HOST_LAUNCH_PURPOSE, - &workspace_coverage_launch_statement(entry)?, - )?; - entry.host_signature = proof.signature; - Ok(()) -} - -pub fn workspace_coverage_heartbeat_statement( - entry: &WorkspaceCoverageProviderHeartbeatEntry, -) -> Result> { - Ok(rmp_serde::to_vec_named(&HeartbeatStatement { - schema_version: &entry.schema_version, - heartbeat_id: &entry.heartbeat_id, - launch_id: &entry.launch_id, - launch_envelope_digest: &entry.launch_envelope_digest, - service_id: &entry.service_id, - provider_daemon_id: &entry.provider_daemon_id, - runtime_id: &entry.runtime_id, - host_identity_id: &entry.host_identity_id, - host_identity_record_digest: &entry.host_identity_record_digest, - boot_identity: &entry.boot_identity, - process_id: entry.process_id, - process_creation_token: entry.process_creation_token, - process_executable_path: &entry.process_executable_path, - provider_incarnation_id: &entry.provider_incarnation_id, - provider_public_key: &entry.provider_public_key, - sequence: entry.sequence, - status: &entry.status, - observed_at_utc: &entry.observed_at_utc, - signature_algorithm: &entry.signature_algorithm, - })?) -} - -pub fn workspace_coverage_termination_statement( - entry: &WorkspaceCoverageProcessTerminationObservationEntry, -) -> Result> { - Ok(rmp_serde::to_vec_named(&TerminationStatement { - schema_version: &entry.schema_version, - termination_id: &entry.termination_id, - launch_id: &entry.launch_id, - launch_envelope_digest: &entry.launch_envelope_digest, - heartbeat_id: &entry.heartbeat_id, - heartbeat_envelope_digest: &entry.heartbeat_envelope_digest, - policy_id: &entry.policy_id, - policy_envelope_digest: &entry.policy_envelope_digest, - runtime_id: &entry.runtime_id, - host_identity_id: &entry.host_identity_id, - host_identity_record_digest: &entry.host_identity_record_digest, - expected_boot_identity: &entry.expected_boot_identity, - expected_process_id: entry.expected_process_id, - expected_process_creation_token: entry.expected_process_creation_token, - expected_process_executable_path: &entry.expected_process_executable_path, - observed_boot_identity: &entry.observed_boot_identity, - outcome: &entry.outcome, - exit_code: entry.exit_code, - replacement_process_id: entry.replacement_process_id, - replacement_process_creation_token: entry.replacement_process_creation_token, - replacement_process_created_at_rfc3339: &entry.replacement_process_created_at_rfc3339, - replacement_process_executable_path: &entry.replacement_process_executable_path, - observed_at_utc: &entry.observed_at_utc, - observer_id: &entry.observer_id, - signature_algorithm: &entry.signature_algorithm, - })?) -} - -pub fn sign_workspace_coverage_termination( - entry: &mut WorkspaceCoverageProcessTerminationObservationEntry, - signer: &HostIdentitySigner, -) -> Result<()> { - entry.host_signature.clear(); - let proof = signer.sign( - HOST_TERMINATION_PURPOSE, - &workspace_coverage_termination_statement(entry)?, - )?; - entry.host_signature = proof.signature; - Ok(()) -} - -pub fn sign_workspace_coverage_heartbeat( - entry: &mut WorkspaceCoverageProviderHeartbeatEntry, - signing_key: &SigningKey, -) -> Result<()> { - if signing_key.verifying_key().to_bytes().as_slice() != entry.provider_public_key.as_slice() { - bail!("provider signing key disagrees with heartbeat public key"); - } - entry.provider_signature.clear(); - let statement = workspace_coverage_heartbeat_statement(entry)?; - entry.provider_signature = signing_key - .sign(&provider_message(&statement)) - .to_bytes() - .to_vec(); - Ok(()) -} - -pub fn process_identity_from_workspace_coverage_launch( - entry: &WorkspaceCoverageManagedProcessLaunchEntry, -) -> ProcessInstanceIdentity { - ProcessInstanceIdentity { - process_id: entry.process_id, - creation_token: entry.process_creation_token, - created_at_rfc3339: entry.process_created_at_rfc3339.clone(), - executable_path: entry.process_executable_path.clone().into(), - } -} - -pub fn write_workspace_coverage_managed_process_launch( - store_path: impl AsRef, - runtime_id: impl Into, - entry: WorkspaceCoverageManagedProcessLaunchEntry, - host_identity: &HostIncarnationIdentityEntry, -) -> Result { - validate_launch(&entry, host_identity)?; - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - if runtime_id != entry.runtime_id { - bail!("workspace coverage launch runtime argument disagrees with signed runtime id"); - } - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let policy_key = managed_policy_key(); - let policy_envelope = node - .cache() - .get_envelope::(&policy_key)? - .ok_or_else(|| anyhow!("workspace coverage managed policy is absent"))?; - let policy: EpiphanyCultMeshManagedServicePolicyEntry = - rmp_serde::from_slice(&policy_envelope.payload)?; - validate_workspace_coverage_projector_managed_service_policy(&policy)?; - if entry.policy_id != policy.policy_id - || entry.policy_envelope_digest != envelope_digest(&policy_envelope) - || entry.command != policy.command - || entry.args != policy.args - || entry.cwd != policy.cwd - { - bail!("workspace coverage launch disagrees with current managed policy"); - } - let identity_key = launch_key(&entry.launch_id); - if let Some(existing) = node.get::(&identity_key)? { - if existing == entry { - return Ok(existing); - } - bail!("workspace coverage launch identity collision"); - } - let evidence_head_key = process_evidence_head_key(&entry.launch_id); - if node - .cache() - .get_envelope::(&evidence_head_key)? - .is_some() - { - bail!("workspace coverage launch evidence head identity collision"); - } - let evidence_head = WorkspaceCoverageProcessEvidenceHead { - schema_version: WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION.into(), - launch_id: entry.launch_id.clone(), - generation: 1, - state: "launched".into(), - heartbeat_id: None, - termination_id: None, - }; - let mut expected = vec![policy_envelope.clone()]; - let mut replacements = vec![ - policy_envelope, - node.cache().prepare_entry(&identity_key, &entry)?.0, - node.cache() - .prepare_entry(&evidence_head_key, &evidence_head)? - .0, - ]; - if let (Some(old_launch_id), Some(termination_id), Some(termination_digest)) = ( - entry.replaces_launch_id.as_deref(), - entry.replaces_termination_id.as_deref(), - entry.replaces_termination_envelope_digest.as_deref(), - ) { - let termination_envelope = node - .cache() - .get_envelope::(&termination_key( - old_launch_id, - ))? - .ok_or_else(|| anyhow!("workspace coverage replacement termination is absent"))?; - let termination: WorkspaceCoverageProcessTerminationObservationEntry = - rmp_serde::from_slice(&termination_envelope.payload)?; - authenticate_workspace_coverage_process_termination_observation( - store_path, - entry.runtime_id.clone(), - old_launch_id, - host_identity, - )?; - if termination.termination_id != termination_id - || envelope_digest(&termination_envelope) != termination_digest - { - bail!("workspace coverage replacement launch disagrees with exact termination"); - } - let replacement_key = - format!("epiphany-local/workspace-coverage/replacement-for/{old_launch_id}"); - if node - .cache() - .get_envelope::(&replacement_key)? - .is_some() - { - bail!("workspace coverage termination already has a replacement launch"); - } - expected.push(termination_envelope.clone()); - replacements.push(termination_envelope); - replacements.push(node.cache().prepare_entry(&replacement_key, &entry)?.0); - } - if let Some(latest) = node - .cache() - .get_envelope::( - WORKSPACE_COVERAGE_PROCESS_LAUNCH_LATEST_KEY, - )? - { - expected.push(latest); - } - replacements.push( - node.cache() - .prepare_entry(WORKSPACE_COVERAGE_PROCESS_LAUNCH_LATEST_KEY, &entry)? - .0, - ); - if !SingleFileMessagePackBackingStore::new(store_path) - .compare_and_swap_batch(&expected, replacements)? - { - bail!("workspace coverage launch lost exact policy/latest compare-and-swap"); - } - Ok(entry) -} - -pub fn write_workspace_coverage_provider_heartbeat( - store_path: impl AsRef, - runtime_id: impl Into, - entry: WorkspaceCoverageProviderHeartbeatEntry, -) -> Result { - validate_heartbeat_shape(&entry)?; - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - if runtime_id != entry.runtime_id { - bail!("workspace coverage heartbeat runtime argument disagrees with signed runtime id"); - } - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let launch_key = launch_key(&entry.launch_id); - let launch_envelope = node - .cache() - .get_envelope::(&launch_key)? - .ok_or_else(|| anyhow!("workspace coverage heartbeat launch is absent"))?; - let launch: WorkspaceCoverageManagedProcessLaunchEntry = - rmp_serde::from_slice(&launch_envelope.payload)?; - authenticate_heartbeat_against_launch(&entry, &launch, &envelope_digest(&launch_envelope))?; - let latest_key = heartbeat_latest_key(&entry.launch_id); - let evidence_key = heartbeat_evidence_key(&entry.launch_id, &entry.heartbeat_id); - let latest = node - .cache() - .get_envelope::(&latest_key)?; - if let Some(existing) = latest.as_ref() { - let existing: WorkspaceCoverageProviderHeartbeatEntry = - rmp_serde::from_slice(&existing.payload)?; - if existing == entry { - return Ok(existing); - } - if existing.heartbeat_id == entry.heartbeat_id { - bail!("workspace coverage heartbeat identity collision"); - } - } - let evidence_head_key = process_evidence_head_key(&entry.launch_id); - let evidence_head_envelope = node - .cache() - .get_envelope::(&evidence_head_key)? - .ok_or_else(|| anyhow!("workspace coverage heartbeat process evidence head is absent"))?; - let evidence_head: WorkspaceCoverageProcessEvidenceHead = - rmp_serde::from_slice(&evidence_head_envelope.payload)?; - validate_process_evidence_head(&evidence_head, &entry.launch_id)?; - if evidence_head.state == "terminated" { - bail!("workspace coverage heartbeat cannot advance a terminated process"); - } - let next_evidence_head = WorkspaceCoverageProcessEvidenceHead { - schema_version: WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION.into(), - launch_id: entry.launch_id.clone(), - generation: evidence_head - .generation - .checked_add(1) - .ok_or_else(|| anyhow!("workspace coverage process evidence generation exhausted"))?, - state: "heartbeat".into(), - heartbeat_id: Some(entry.heartbeat_id.clone()), - termination_id: None, - }; - let mut expected = vec![launch_envelope.clone(), evidence_head_envelope.clone()]; - let mut replacements = vec![ - launch_envelope, - node.cache() - .prepare_entry(&evidence_head_key, &next_evidence_head)? - .0, - ]; - if node - .cache() - .get_envelope::(&evidence_key)? - .is_some() - { - bail!("workspace coverage heartbeat immutable evidence identity collision"); - } - match latest.as_ref() { - Some(envelope) => { - let prior: WorkspaceCoverageProviderHeartbeatEntry = - rmp_serde::from_slice(&envelope.payload)?; - if entry.sequence - != prior - .sequence - .checked_add(1) - .ok_or_else(|| anyhow!("workspace coverage heartbeat sequence exhausted"))? - { - bail!( - "workspace coverage heartbeat sequence must exactly advance latest launch sequence" - ); - } - let prior_time = DateTime::parse_from_rfc3339(&prior.observed_at_utc)?; - let current_time = DateTime::parse_from_rfc3339(&entry.observed_at_utc)?; - if current_time <= prior_time { - bail!("workspace coverage heartbeat time must strictly advance"); - } - expected.push(envelope.clone()); - } - None if entry.sequence != 1 => { - bail!("first workspace coverage heartbeat must have sequence one") - } - None => {} - } - replacements.push(node.cache().prepare_entry(&latest_key, &entry)?.0); - replacements.push(node.cache().prepare_entry(&evidence_key, &entry)?.0); - if !SingleFileMessagePackBackingStore::new(store_path) - .compare_and_swap_batch(&expected, replacements)? - { - bail!("workspace coverage heartbeat lost exact launch/latest compare-and-swap"); - } - Ok(entry) -} - -pub fn load_workspace_coverage_managed_process_launch( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, -) -> Result> { - require_nonempty("launch id", launch_id)?; - open_epiphany_cultmesh_node(store_path, runtime_id)?.get(&launch_key(launch_id)) -} - -pub fn load_workspace_coverage_managed_process_launch_with_digest( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, -) -> Result> { - require_nonempty("launch id", launch_id)?; - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let Some(envelope) = node - .cache() - .get_envelope::(&launch_key(launch_id))? - else { - return Ok(None); - }; - let digest = envelope_digest(&envelope); - Ok(Some((rmp_serde::from_slice(&envelope.payload)?, digest))) -} - -pub fn load_latest_workspace_coverage_managed_process_launch( - store_path: impl AsRef, - runtime_id: impl Into, -) -> Result> { - open_epiphany_cultmesh_node(store_path, runtime_id)? - .get(WORKSPACE_COVERAGE_PROCESS_LAUNCH_LATEST_KEY) -} - -pub fn load_workspace_coverage_provider_heartbeat( - store_path: impl AsRef, - runtime_id: impl Into, - heartbeat_id: &str, -) -> Result> { - require_nonempty("heartbeat id", heartbeat_id)?; - let runtime_id = runtime_id.into(); - let Some(envelope) = latest_heartbeat_envelope_by_id(store_path, &runtime_id, heartbeat_id)? - else { - return Ok(None); - }; - Ok(Some(rmp_serde::from_slice(&envelope.payload)?)) -} - -pub fn load_latest_workspace_coverage_provider_heartbeat( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, -) -> Result> { - require_nonempty("launch id", launch_id)?; - open_epiphany_cultmesh_node(store_path, runtime_id)?.get(&heartbeat_latest_key(launch_id)) -} - -pub fn authenticate_workspace_coverage_managed_process_launch( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result { - let runtime_id = runtime_id.into(); - let entry = load_workspace_coverage_managed_process_launch( - store_path.as_ref(), - runtime_id.clone(), - launch_id, - )? - .ok_or_else(|| anyhow!("workspace coverage managed process launch is absent"))?; - if runtime_id != entry.runtime_id { - bail!("workspace coverage launch runtime argument disagrees with signed runtime id"); - } - validate_launch(&entry, host_identity)?; - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let envelope = node - .cache() - .get_envelope::(&managed_policy_key())? - .ok_or_else(|| anyhow!("workspace coverage managed policy is absent"))?; - let policy: EpiphanyCultMeshManagedServicePolicyEntry = - rmp_serde::from_slice(&envelope.payload)?; - validate_workspace_coverage_projector_managed_service_policy(&policy)?; - if entry.policy_id != policy.policy_id - || entry.policy_envelope_digest != envelope_digest(&envelope) - || entry.command != policy.command - || entry.args != policy.args - || entry.cwd != policy.cwd - { - bail!("workspace coverage launch disagrees with current managed policy"); - } - Ok(entry) -} - -pub fn authenticate_historical_workspace_coverage_managed_process_launch( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result { - let runtime_id = runtime_id.into(); - let entry = - load_workspace_coverage_managed_process_launch(store_path, runtime_id.clone(), launch_id)? - .ok_or_else(|| anyhow!("workspace coverage managed process launch is absent"))?; - if entry.runtime_id != runtime_id { - bail!("workspace coverage launch runtime argument disagrees with signed runtime id"); - } - validate_launch(&entry, host_identity)?; - Ok(entry) -} - -pub fn authenticate_workspace_coverage_provider_heartbeat( - store_path: impl AsRef, - runtime_id: impl Into, - heartbeat_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result { - let runtime_id = runtime_id.into(); - let heartbeat = load_workspace_coverage_provider_heartbeat( - store_path.as_ref(), - runtime_id.clone(), - heartbeat_id, - )? - .ok_or_else(|| anyhow!("workspace coverage provider heartbeat is absent"))?; - if runtime_id != heartbeat.runtime_id { - bail!("workspace coverage heartbeat runtime argument disagrees with signed runtime id"); - } - let launch = authenticate_workspace_coverage_managed_process_launch( - store_path.as_ref(), - runtime_id.clone(), - &heartbeat.launch_id, - host_identity, - )?; - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let envelope = node - .cache() - .get_envelope::(&launch_key( - &heartbeat.launch_id, - ))? - .ok_or_else(|| anyhow!("workspace coverage launch envelope disappeared"))?; - authenticate_heartbeat_against_launch(&heartbeat, &launch, &envelope_digest(&envelope))?; - Ok(heartbeat) -} - -pub(crate) fn authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result<(WorkspaceCoverageManagedProcessLaunchEntry, String)> { - let runtime_id = runtime_id.into(); - let launch = authenticate_workspace_coverage_managed_process_launch( - store_path.as_ref(), - runtime_id.clone(), - launch_id, - host_identity, - )?; - let envelope = open_epiphany_cultmesh_node(store_path, runtime_id)? - .cache() - .get_envelope::(&launch_key(launch_id))? - .ok_or_else(|| anyhow!("workspace coverage launch envelope disappeared"))?; - Ok((launch, envelope_digest(&envelope))) -} - -pub(crate) fn authenticate_historical_workspace_coverage_managed_process_launch_with_envelope_digest( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result<(WorkspaceCoverageManagedProcessLaunchEntry, String)> { - let runtime_id = runtime_id.into(); - let launch = authenticate_historical_workspace_coverage_managed_process_launch( - store_path.as_ref(), - runtime_id.clone(), - launch_id, - host_identity, - )?; - let envelope = open_epiphany_cultmesh_node(store_path, runtime_id)? - .cache() - .get_envelope::(&launch_key(launch_id))? - .ok_or_else(|| anyhow!("historical workspace coverage launch envelope disappeared"))?; - Ok((launch, envelope_digest(&envelope))) -} - -pub fn authenticate_workspace_coverage_replacement_lineage( - store_path: impl AsRef, - runtime_id: &str, - old_launch_id: &str, - replacement_launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result<()> { - let store_path = store_path.as_ref(); - if old_launch_id == replacement_launch_id { - bail!("workspace coverage replacement lineage did not advance"); - } - authenticate_historical_workspace_coverage_managed_process_launch( - store_path, - runtime_id.to_string(), - old_launch_id, - host_identity, - )?; - let mut cursor = replacement_launch_id.to_string(); - let mut visited = std::collections::BTreeSet::new(); - loop { - if !visited.insert(cursor.clone()) { - bail!("workspace coverage replacement lineage contains a cycle"); - } - let child = if cursor == replacement_launch_id { - authenticate_workspace_coverage_managed_process_launch( - store_path, - runtime_id.to_string(), - &cursor, - host_identity, - )? - } else { - authenticate_historical_workspace_coverage_managed_process_launch( - store_path, - runtime_id.to_string(), - &cursor, - host_identity, - )? - }; - let parent_id = child.replaces_launch_id.as_deref().ok_or_else(|| { - anyhow!("workspace coverage replacement lineage ended before the claimed launch") - })?; - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - store_path, - runtime_id.to_string(), - parent_id, - host_identity, - )?; - if child.replaces_termination_id.as_deref() != Some(termination.termination_id.as_str()) - || child.replaces_termination_envelope_digest.as_deref() - != Some(termination_digest.as_str()) - { - bail!("workspace coverage replacement lineage has a broken termination edge"); - } - let terminated_at = chrono::DateTime::parse_from_rfc3339(&termination.observed_at_utc)?; - let launched_at = chrono::DateTime::parse_from_rfc3339(&child.launched_at_utc)?; - if terminated_at >= launched_at { - bail!("workspace coverage replacement lineage violates termination ordering"); - } - if parent_id == old_launch_id { - return Ok(()); - } - authenticate_historical_workspace_coverage_managed_process_launch( - store_path, - runtime_id.to_string(), - parent_id, - host_identity, - )?; - cursor = parent_id.to_string(); - } -} - -pub fn observe_workspace_coverage_managed_process( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result { - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - let launch = authenticate_workspace_coverage_managed_process_launch( - store_path, - runtime_id.clone(), - launch_id, - host_identity, - )?; - let policy_envelope = open_epiphany_cultmesh_node(store_path, runtime_id)? - .cache() - .get_envelope::(&managed_policy_key())? - .ok_or_else(|| anyhow!("workspace coverage managed policy is absent"))?; - let policy: EpiphanyCultMeshManagedServicePolicyEntry = - rmp_serde::from_slice(&policy_envelope.payload)?; - validate_workspace_coverage_projector_managed_service_policy(&policy)?; - if launch.policy_id != policy.policy_id - || launch.policy_envelope_digest != envelope_digest(&policy_envelope) - || launch.command != policy.command - || launch.args != policy.args - || launch.cwd != policy.cwd - { - bail!("workspace coverage observed launch disagrees with current managed policy"); - } - Ok(observe_workspace_coverage_process_with_source( - &launch, - &NativeWorkspaceCoverageProcessObservationSource, - )) -} - -pub fn observe_historical_workspace_coverage_managed_process( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result { - let launch = authenticate_historical_workspace_coverage_managed_process_launch( - store_path, - runtime_id, - launch_id, - host_identity, - )?; - Ok(observe_workspace_coverage_process_with_source( - &launch, - &NativeWorkspaceCoverageProcessObservationSource, - )) -} - -pub(crate) fn authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest( - store_path: impl AsRef, - runtime_id: impl Into, - heartbeat_id: &str, - host_identity: &HostIncarnationIdentityEntry, -) -> Result<(WorkspaceCoverageProviderHeartbeatEntry, String)> { - let runtime_id = runtime_id.into(); - let heartbeat = authenticate_workspace_coverage_provider_heartbeat( - store_path.as_ref(), - runtime_id.clone(), - heartbeat_id, - host_identity, - )?; - let envelope = latest_heartbeat_envelope_by_id(store_path, &runtime_id, heartbeat_id)? - .ok_or_else(|| anyhow!("workspace coverage heartbeat envelope disappeared"))?; - Ok((heartbeat, envelope_digest(&envelope))) -} - -pub fn write_workspace_coverage_process_termination_observation( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host: &HostIdentitySigner, -) -> Result { - write_workspace_coverage_process_termination_observation_with_source( - store_path, - runtime_id, - launch_id, - host, - &NativeWorkspaceCoverageProcessObservationSource, - ) -} - -fn write_workspace_coverage_process_termination_observation_with_source( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host: &HostIdentitySigner, - source: &dyn WorkspaceCoverageProcessObservationSource, -) -> Result { - require_nonempty("launch id", launch_id)?; - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - let node = open_epiphany_cultmesh_node(store_path, runtime_id.clone())?; - - let launch_envelope = node - .cache() - .get_envelope::(&launch_key(launch_id))? - .ok_or_else(|| anyhow!("workspace coverage managed process launch is absent"))?; - let launch: WorkspaceCoverageManagedProcessLaunchEntry = - rmp_serde::from_slice(&launch_envelope.payload)?; - validate_launch(&launch, host.entry())?; - if launch.runtime_id != runtime_id { - bail!("workspace coverage termination launch runtime disagrees with signed identity"); - } - - let evidence_head_key = process_evidence_head_key(launch_id); - let evidence_head_envelope = node - .cache() - .get_envelope::(&evidence_head_key)? - .ok_or_else(|| anyhow!("workspace coverage termination process evidence head is absent"))?; - let evidence_head: WorkspaceCoverageProcessEvidenceHead = - rmp_serde::from_slice(&evidence_head_envelope.payload)?; - validate_process_evidence_head(&evidence_head, launch_id)?; - if evidence_head.state == "terminated" { - bail!("workspace coverage process already has terminal evidence"); - } - let heartbeat_evidence = if let Some(heartbeat_id) = evidence_head.heartbeat_id.as_deref() { - let envelope = node - .cache() - .get_envelope::(&heartbeat_latest_key( - launch_id, - ))? - .ok_or_else(|| anyhow!("workspace coverage evidence head heartbeat is absent"))?; - let heartbeat: WorkspaceCoverageProviderHeartbeatEntry = - rmp_serde::from_slice(&envelope.payload)?; - authenticate_heartbeat_against_launch( - &heartbeat, - &launch, - &envelope_digest(&launch_envelope), - )?; - if heartbeat.heartbeat_id != heartbeat_id { - bail!("workspace coverage evidence head disagrees with latest heartbeat"); - } - Some((envelope, heartbeat)) - } else { - None - }; - - let observation = observe_workspace_coverage_process_with_source(&launch, source); - let (observed_boot_identity, outcome, exit_code, replacement) = match observation { - WorkspaceCoverageProcessLifecycleObservation::BootSuperseded { - observed_boot_identity, - } => (observed_boot_identity, "boot_superseded", None, None), - WorkspaceCoverageProcessLifecycleObservation::ExactExited { exit_code } => ( - launch.boot_identity.clone(), - "exact_exited", - exit_code, - None, - ), - WorkspaceCoverageProcessLifecycleObservation::Missing => { - (launch.boot_identity.clone(), "process_missing", None, None) - } - WorkspaceCoverageProcessLifecycleObservation::Replaced { observed } => ( - launch.boot_identity.clone(), - "process_replaced", - None, - Some(observed), - ), - WorkspaceCoverageProcessLifecycleObservation::ExactAlive => { - bail!("exact workspace coverage process instance is still alive") - } - WorkspaceCoverageProcessLifecycleObservation::Inaccessible => { - bail!("workspace coverage process observation is inaccessible") - } - WorkspaceCoverageProcessLifecycleObservation::Indeterminate { reason } => { - bail!("workspace coverage process termination is indeterminate: {reason}") - } - }; - let observed_at_utc = chrono::Utc::now().to_rfc3339(); - let mut entry = WorkspaceCoverageProcessTerminationObservationEntry { - schema_version: WORKSPACE_COVERAGE_PROCESS_TERMINATION_SCHEMA_VERSION.to_string(), - termination_id: launch.launch_id.clone(), - launch_id: launch.launch_id.clone(), - launch_envelope_digest: envelope_digest(&launch_envelope), - heartbeat_id: heartbeat_evidence - .as_ref() - .map(|(_, heartbeat)| heartbeat.heartbeat_id.clone()), - heartbeat_envelope_digest: heartbeat_evidence - .as_ref() - .map(|(envelope, _)| envelope_digest(envelope)), - policy_id: launch.policy_id.clone(), - policy_envelope_digest: launch.policy_envelope_digest.clone(), - runtime_id, - host_identity_id: host.entry().identity_id.clone(), - host_identity_record_digest: workspace_coverage_host_identity_record_digest(host.entry())?, - expected_boot_identity: launch.boot_identity.clone(), - expected_process_id: launch.process_id, - expected_process_creation_token: launch.process_creation_token, - expected_process_executable_path: launch.process_executable_path.clone(), - observed_boot_identity, - outcome: outcome.to_string(), - exit_code, - replacement_process_id: replacement.as_ref().map(|value| value.process_id), - replacement_process_creation_token: replacement.as_ref().map(|value| value.creation_token), - replacement_process_created_at_rfc3339: replacement - .as_ref() - .and_then(|value| value.created_at_rfc3339.clone()), - replacement_process_executable_path: replacement - .as_ref() - .map(|value| value.executable_path.display().to_string()), - observed_at_utc, - observer_id: WORKSPACE_COVERAGE_TERMINATION_OBSERVER.to_string(), - host_signature: Vec::new(), - signature_algorithm: "ed25519".to_string(), - }; - sign_workspace_coverage_termination(&mut entry, host)?; - validate_termination(&entry, host.entry())?; - - let key = termination_key(launch_id); - let terminal_head = WorkspaceCoverageProcessEvidenceHead { - schema_version: WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION.into(), - launch_id: launch_id.into(), - generation: evidence_head - .generation - .checked_add(1) - .ok_or_else(|| anyhow!("workspace coverage process evidence generation exhausted"))?, - state: "terminated".into(), - heartbeat_id: evidence_head.heartbeat_id.clone(), - termination_id: Some(entry.termination_id.clone()), - }; - let replacement = node.cache().prepare_entry(&key, &entry)?.0; - let mut expected = vec![launch_envelope.clone(), evidence_head_envelope]; - let mut replacements = vec![ - launch_envelope, - node.cache() - .prepare_entry(&evidence_head_key, &terminal_head)? - .0, - replacement, - ]; - if let Some((heartbeat_envelope, _)) = heartbeat_evidence { - expected.push(heartbeat_envelope.clone()); - replacements.push(heartbeat_envelope); - } - if !SingleFileMessagePackBackingStore::new(store_path) - .compare_and_swap_batch(&expected, replacements)? - { - bail!("workspace coverage termination lost exact launch/heartbeat CAS or collided"); - } - Ok(entry) -} - -pub fn load_workspace_coverage_process_termination_observation( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, -) -> Result> { - require_nonempty("launch id", launch_id)?; - open_epiphany_cultmesh_node(store_path, runtime_id)?.get(&termination_key(launch_id)) -} - -pub fn authenticate_workspace_coverage_process_termination_observation( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result { - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - let entry = load_workspace_coverage_process_termination_observation( - store_path, - runtime_id.clone(), - launch_id, - )? - .ok_or_else(|| anyhow!("workspace coverage process termination observation is absent"))?; - validate_termination(&entry, host)?; - if entry.runtime_id != runtime_id || entry.launch_id != launch_id { - bail!("workspace coverage termination request disagrees with signed identity"); - } - let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; - let launch_envelope = node - .cache() - .get_envelope::(&launch_key(launch_id))? - .ok_or_else(|| anyhow!("workspace coverage termination launch evidence is absent"))?; - let launch: WorkspaceCoverageManagedProcessLaunchEntry = - rmp_serde::from_slice(&launch_envelope.payload)?; - validate_launch(&launch, host)?; - let evidence_head: WorkspaceCoverageProcessEvidenceHead = node - .get(&process_evidence_head_key(launch_id))? - .ok_or_else(|| anyhow!("workspace coverage termination process evidence head is absent"))?; - validate_process_evidence_head(&evidence_head, launch_id)?; - if evidence_head.state != "terminated" - || evidence_head.termination_id.as_deref() != Some(entry.termination_id.as_str()) - || evidence_head.heartbeat_id != entry.heartbeat_id - { - bail!("workspace coverage termination disagrees with process evidence head"); - } - let heartbeat_evidence = match ( - entry.heartbeat_id.as_deref(), - entry.heartbeat_envelope_digest.as_deref(), - ) { - (Some(heartbeat_id), Some(expected_digest)) => { - let envelope = node - .cache() - .get_envelope::(&heartbeat_latest_key( - launch_id, - ))? - .ok_or_else(|| { - anyhow!("workspace coverage termination heartbeat evidence is absent") - })?; - let heartbeat: WorkspaceCoverageProviderHeartbeatEntry = - rmp_serde::from_slice(&envelope.payload)?; - authenticate_heartbeat_against_launch( - &heartbeat, - &launch, - &envelope_digest(&launch_envelope), - )?; - if heartbeat.heartbeat_id != heartbeat_id - || envelope_digest(&envelope) != expected_digest - { - bail!("workspace coverage termination heartbeat evidence disagrees"); - } - Some(heartbeat) - } - (None, None) => None, - _ => bail!("workspace coverage termination has partial heartbeat evidence"), - }; - if entry.policy_id != launch.policy_id - || launch.policy_envelope_digest != entry.policy_envelope_digest - || entry.launch_envelope_digest != envelope_digest(&launch_envelope) - || entry.host_identity_id != launch.host_identity_id - || entry.host_identity_record_digest != launch.host_identity_record_digest - || entry.expected_boot_identity != launch.boot_identity - || entry.expected_process_id != launch.process_id - || entry.expected_process_creation_token != launch.process_creation_token - || entry.expected_process_executable_path != launch.process_executable_path - { - bail!("workspace coverage termination evidence chain disagrees with its exact sources"); - } - if heartbeat_evidence - .as_ref() - .map(|heartbeat| heartbeat.heartbeat_id.as_str()) - != entry.heartbeat_id.as_deref() - { - bail!("workspace coverage termination heartbeat identity disagrees"); - } - Ok(entry) -} - -pub fn authenticate_workspace_coverage_termination_with_envelope_digest( - store_path: impl AsRef, - runtime_id: impl Into, - launch_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result<(WorkspaceCoverageProcessTerminationObservationEntry, String)> { - let store_path = store_path.as_ref(); - let runtime_id = runtime_id.into(); - let entry = authenticate_workspace_coverage_process_termination_observation( - store_path, - runtime_id.clone(), - launch_id, - host, - )?; - let envelope = open_epiphany_cultmesh_node(store_path, runtime_id)? - .cache() - .get_envelope::(&termination_key( - launch_id, - ))? - .ok_or_else(|| anyhow!("workspace coverage termination envelope disappeared"))?; - Ok((entry, envelope_digest(&envelope))) -} - -fn validate_launch( - entry: &WorkspaceCoverageManagedProcessLaunchEntry, - host: &HostIncarnationIdentityEntry, -) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION - || entry.service_id != EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID - || entry.provider_daemon_id != EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID - || entry.supervisor_id != "epiphany-daemon-supervisor" - { - bail!("workspace coverage launch violates its reserved schema or authority"); - } - match ( - entry.replaces_launch_id.as_deref(), - entry.replaces_termination_id.as_deref(), - entry.replaces_termination_envelope_digest.as_deref(), - ) { - (None, None, None) => {} - (Some(launch_id), Some(termination_id), Some(digest)) - if !launch_id.trim().is_empty() && !termination_id.trim().is_empty() => - { - validate_digest("replacement termination", digest)?; - } - _ => bail!("workspace coverage replacement launch has a partial causal edge"), - } - for (name, value) in [ - ("launch id", entry.launch_id.as_str()), - ("runtime id", entry.runtime_id.as_str()), - ("policy id", entry.policy_id.as_str()), - ("policy digest", entry.policy_envelope_digest.as_str()), - ("command", entry.command.as_str()), - ("launch time", entry.launched_at_utc.as_str()), - ("boot identity", entry.boot_identity.as_str()), - ( - "process executable path", - entry.process_executable_path.as_str(), - ), - ("executable digest", entry.executable_sha256.as_str()), - ( - "provider incarnation id", - entry.provider_incarnation_id.as_str(), - ), - ("supervisor id", entry.supervisor_id.as_str()), - ] { - require_nonempty(name, value)?; - } - DateTime::parse_from_rfc3339(&entry.launched_at_utc) - .context("workspace coverage launch time must be RFC3339")?; - let identity_captured_at = DateTime::parse_from_rfc3339(&entry.identity_captured_at_utc) - .context("process identity capture time must be RFC3339")?; - if identity_captured_at < DateTime::parse_from_rfc3339(&entry.launched_at_utc)? { - bail!("process identity cannot be captured before launch"); - } - if let Some(created) = &entry.process_created_at_rfc3339 { - DateTime::parse_from_rfc3339(created).context("process creation time must be RFC3339")?; - } - uuid::Uuid::parse_str(&entry.launch_id).context("launch id must be UUID")?; - uuid::Uuid::parse_str(&entry.provider_incarnation_id) - .context("provider incarnation id must be UUID")?; - validate_digest("policy", &entry.policy_envelope_digest)?; - validate_digest("host identity record", &entry.host_identity_record_digest)?; - validate_digest("executable", &entry.executable_sha256)?; - validate_absolute_path(&entry.process_executable_path)?; - if entry.signature_algorithm != "ed25519" - || entry.process_id == 0 - || entry.process_creation_token == 0 - || entry.provider_public_key.len() != 32 - || entry.host_signature.len() != 64 - { - bail!("workspace coverage launch has invalid process identity or signature material"); - } - if entry.host_identity_id != host.identity_id - || entry.host_public_key != host.public_key - || entry.host_assurance != host.assurance - || entry.host_identity_record_digest - != workspace_coverage_host_identity_record_digest(host)? - { - bail!("workspace coverage launch disagrees with enrolled host public record"); - } - verify_host_identity_signature( - host, - HOST_LAUNCH_PURPOSE, - &workspace_coverage_launch_statement(entry)?, - &HostIdentitySignature { - identity_id: entry.host_identity_id.clone(), - signature: entry.host_signature.clone(), - }, - )?; - Ok(()) -} - -fn validate_heartbeat_shape(entry: &WorkspaceCoverageProviderHeartbeatEntry) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION - || entry.service_id != EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID - || entry.provider_daemon_id != EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID - { - bail!("workspace coverage heartbeat violates its reserved schema or authority"); - } - for (name, value) in [ - ("heartbeat id", entry.heartbeat_id.as_str()), - ("launch id", entry.launch_id.as_str()), - ("launch digest", entry.launch_envelope_digest.as_str()), - ("runtime id", entry.runtime_id.as_str()), - ("host identity id", entry.host_identity_id.as_str()), - ( - "host identity record digest", - entry.host_identity_record_digest.as_str(), - ), - ("boot identity", entry.boot_identity.as_str()), - ( - "process executable path", - entry.process_executable_path.as_str(), - ), - ( - "provider incarnation id", - entry.provider_incarnation_id.as_str(), - ), - ("status", entry.status.as_str()), - ("observation time", entry.observed_at_utc.as_str()), - ] { - require_nonempty(name, value)?; - } - DateTime::parse_from_rfc3339(&entry.observed_at_utc) - .context("workspace coverage heartbeat time must be RFC3339")?; - uuid::Uuid::parse_str(&entry.heartbeat_id).context("heartbeat id must be UUID")?; - uuid::Uuid::parse_str(&entry.launch_id).context("heartbeat launch id must be UUID")?; - uuid::Uuid::parse_str(&entry.provider_incarnation_id) - .context("heartbeat provider incarnation id must be UUID")?; - validate_digest("launch", &entry.launch_envelope_digest)?; - validate_digest("host identity record", &entry.host_identity_record_digest)?; - validate_absolute_path(&entry.process_executable_path)?; - if !matches!(entry.status.as_str(), "ready" | "degraded" | "stopping") { - bail!("workspace coverage heartbeat status is not authoritative"); - } - if entry.signature_algorithm != "ed25519" - || entry.sequence == 0 - || entry.process_id == 0 - || entry.process_creation_token == 0 - || entry.provider_public_key.len() != 32 - || entry.provider_signature.len() != 64 - { - bail!("workspace coverage heartbeat has invalid process identity or signature material"); - } - Ok(()) -} - -fn authenticate_heartbeat_against_launch( - heartbeat: &WorkspaceCoverageProviderHeartbeatEntry, - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - launch_digest: &str, -) -> Result<()> { - validate_heartbeat_shape(heartbeat)?; - let observed = DateTime::parse_from_rfc3339(&heartbeat.observed_at_utc)?; - let launched = DateTime::parse_from_rfc3339(&launch.launched_at_utc)?; - let captured = DateTime::parse_from_rfc3339(&launch.identity_captured_at_utc)?; - if observed < launched || observed < captured { - bail!("workspace coverage heartbeat predates its launch identity"); - } - if heartbeat.launch_envelope_digest != launch_digest - || heartbeat.launch_id != launch.launch_id - || heartbeat.service_id != launch.service_id - || heartbeat.provider_daemon_id != launch.provider_daemon_id - || heartbeat.runtime_id != launch.runtime_id - || heartbeat.host_identity_id != launch.host_identity_id - || heartbeat.host_identity_record_digest != launch.host_identity_record_digest - || heartbeat.boot_identity != launch.boot_identity - || heartbeat.process_id != launch.process_id - || heartbeat.process_creation_token != launch.process_creation_token - || heartbeat.process_executable_path != launch.process_executable_path - || heartbeat.provider_incarnation_id != launch.provider_incarnation_id - || heartbeat.provider_public_key != launch.provider_public_key - { - bail!("workspace coverage heartbeat disagrees with its exact launch identity"); - } - let key: [u8; 32] = heartbeat - .provider_public_key - .as_slice() - .try_into() - .map_err(|_| anyhow!("provider public key has invalid length"))?; - let sig = Signature::from_slice(&heartbeat.provider_signature) - .map_err(|_| anyhow!("provider signature has invalid length"))?; - VerifyingKey::from_bytes(&key)? - .verify( - &provider_message(&workspace_coverage_heartbeat_statement(heartbeat)?), - &sig, - ) - .map_err(|_| anyhow!("workspace coverage heartbeat provider signature verification failed")) -} - -fn provider_message(statement: &[u8]) -> Vec { - let mut out = Vec::with_capacity(PROVIDER_HEARTBEAT_DOMAIN.len() + 8 + statement.len()); - out.extend_from_slice(PROVIDER_HEARTBEAT_DOMAIN); - out.extend_from_slice(&(statement.len() as u64).to_be_bytes()); - out.extend_from_slice(statement); - out -} - -fn validate_termination( - entry: &WorkspaceCoverageProcessTerminationObservationEntry, - host: &HostIncarnationIdentityEntry, -) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_PROCESS_TERMINATION_SCHEMA_VERSION - || entry.observer_id != WORKSPACE_COVERAGE_TERMINATION_OBSERVER - || entry.termination_id != entry.launch_id - || entry.runtime_id.trim().is_empty() - { - bail!("workspace coverage termination violates its reserved authority"); - } - uuid::Uuid::parse_str(&entry.launch_id).context("termination launch id must be UUID")?; - match ( - entry.heartbeat_id.as_deref(), - entry.heartbeat_envelope_digest.as_deref(), - ) { - (Some(id), Some(digest)) => { - uuid::Uuid::parse_str(id).context("termination heartbeat id must be UUID")?; - validate_digest("heartbeat", digest)?; - } - (None, None) => {} - _ => bail!("termination heartbeat evidence is partial"), - } - DateTime::parse_from_rfc3339(&entry.observed_at_utc) - .context("termination observation time must be RFC3339")?; - for (label, digest) in [ - ("launch", &entry.launch_envelope_digest), - ("policy", &entry.policy_envelope_digest), - ("host identity record", &entry.host_identity_record_digest), - ] { - validate_digest(label, digest)?; - } - for (label, value) in [ - ("policy id", entry.policy_id.as_str()), - ("host identity id", entry.host_identity_id.as_str()), - ( - "expected boot identity", - entry.expected_boot_identity.as_str(), - ), - ( - "observed boot identity", - entry.observed_boot_identity.as_str(), - ), - ] { - require_nonempty(label, value)?; - } - validate_absolute_path(&entry.expected_process_executable_path)?; - if entry.expected_process_id == 0 || entry.expected_process_creation_token == 0 { - bail!("termination expected process identity is invalid"); - } - match entry.outcome.as_str() { - "exact_exited" => { - if replacement_fields_present(entry) { - bail!("exact exit must not carry a replacement process identity"); - } - } - "process_missing" => { - if entry.exit_code.is_some() || replacement_fields_present(entry) { - bail!("missing process must not carry exit or replacement material"); - } - } - "process_replaced" => { - if entry.exit_code.is_some() - || entry.replacement_process_id.unwrap_or(0) == 0 - || entry.replacement_process_creation_token.unwrap_or(0) == 0 - || entry.replacement_process_executable_path.is_none() - { - bail!("replaced process requires one complete replacement identity"); - } - validate_absolute_path( - entry - .replacement_process_executable_path - .as_deref() - .unwrap_or_default(), - )?; - if entry.replacement_process_id == Some(entry.expected_process_id) - && entry.replacement_process_creation_token - == Some(entry.expected_process_creation_token) - && entry.replacement_process_executable_path.as_deref() - == Some(entry.expected_process_executable_path.as_str()) - { - bail!("replacement process identity must differ from the terminated instance"); - } - } - "boot_superseded" => { - if entry.observed_boot_identity == entry.expected_boot_identity - || entry.exit_code.is_some() - || replacement_fields_present(entry) - { - bail!("boot supersession requires two distinct boot identities only"); - } - } - _ => bail!("workspace coverage termination outcome is not authoritative"), - } - if entry.outcome != "boot_superseded" - && entry.observed_boot_identity != entry.expected_boot_identity - { - bail!("same-boot process outcome disagrees with the expected boot identity"); - } - if entry.signature_algorithm != "ed25519" - || entry.host_signature.len() != 64 - || entry.host_identity_id != host.identity_id - || entry.host_identity_record_digest - != workspace_coverage_host_identity_record_digest(host)? - { - bail!("workspace coverage termination host signature material is invalid"); - } - verify_host_identity_signature( - host, - HOST_TERMINATION_PURPOSE, - &workspace_coverage_termination_statement(entry)?, - &HostIdentitySignature { - identity_id: entry.host_identity_id.clone(), - signature: entry.host_signature.clone(), - }, - ) -} - -fn replacement_fields_present(entry: &WorkspaceCoverageProcessTerminationObservationEntry) -> bool { - entry.replacement_process_id.is_some() - || entry.replacement_process_creation_token.is_some() - || entry.replacement_process_created_at_rfc3339.is_some() - || entry.replacement_process_executable_path.is_some() -} - -fn require_nonempty(name: &str, value: &str) -> Result<()> { - if value.trim().is_empty() { - bail!("workspace coverage {name} is required"); - } - Ok(()) -} - -fn claim_sight_key(runtime_id: &str, body_generation: u64, body_observation_id: &str) -> String { - format!( - "epiphany-local/workspace-coverage/claim-sight/{runtime_id}/{body_generation}/{body_observation_id}" - ) -} - -fn validate_claim_sight_shape( - entry: &WorkspaceCoverageClaimSightEntry, - signed: bool, -) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_CLAIM_SIGHT_SCHEMA_VERSION - || entry.claim_epoch == 0 - || entry.signature_algorithm != "ed25519" - || entry.provider_public_key.len() != 32 - || signed != (entry.provider_signature.len() == 64) - { - bail!("workspace coverage claim sight violates its reserved schema or signature shape"); - } - for (name, value) in [ - ("runtime id", entry.runtime_id.as_str()), - ("workspace id", entry.workspace_id.as_str()), - ("launch id", entry.launch_id.as_str()), - ("claim id", entry.claim_id.as_str()), - ("attempt id", entry.attempt_id.as_str()), - ("plan id", entry.plan_id.as_str()), - ("Body observation id", entry.body_observation_id.as_str()), - ] { - require_nonempty(name, value)?; - } - uuid::Uuid::parse_str(&entry.launch_id).context("claim sight launch id must be UUID")?; - uuid::Uuid::parse_str(&entry.claim_id).context("claim sight claim id must be UUID")?; - uuid::Uuid::parse_str(&entry.attempt_id).context("claim sight attempt id must be UUID")?; - DateTime::parse_from_rfc3339(&entry.observed_at_utc) - .context("claim sight observation time must be RFC3339")?; - Ok(()) -} - -pub(crate) fn publish_workspace_coverage_claim_sight( - local_verse_store: &Path, - runtime_store: &Path, - coverage: &crate::WorkspaceCoverageAuthority, - acquisition: &crate::workspace_coverage_projector::WorkspaceCoverageAcquisition, - runtime_id: &str, - launch_id: &str, - trusted_host: &HostIncarnationIdentityEntry, - provider: &SigningKey, - observed_at: chrono::DateTime, -) -> Result { - if acquisition.claim.status != "running" - || acquisition.claim.managed_process_launch_id != launch_id - || acquisition.claim.attempt_id != acquisition.attempt.attempt_id - { - bail!("claim sight requires the projector's exact running claim and attempt"); - } - let opening = coverage.store.pull_all()?; - let attempt_env = opening - .iter() - .find(|env| { - env.r#type == "gamecult.epiphany.workspace_coverage_projection_attempt" - && env.key == acquisition.attempt.attempt_id - }) - .ok_or_else(|| anyhow!("claim sight attempt envelope is absent"))?; - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - runtime_id, - launch_id, - trusted_host, - )?; - if launch.provider_public_key.as_slice() != provider.verifying_key().to_bytes() - || launch.provider_incarnation_id != acquisition.claim.executor_incarnation - { - bail!("claim sight provider disagrees with its authenticated launch"); - } - let basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let mut entry = WorkspaceCoverageClaimSightEntry { - schema_version: WORKSPACE_COVERAGE_CLAIM_SIGHT_SCHEMA_VERSION.into(), - runtime_id: runtime_id.into(), - workspace_id: basis.workspace_id, - launch_id: launch_id.into(), - launch_envelope_digest: launch_digest, - provider_incarnation_id: launch.provider_incarnation_id, - provider_public_key: launch.provider_public_key, - coverage_store_binding_id: coverage.store_binding.binding_id.clone(), - coverage_store_binding_envelope_digest: coverage.store_binding_envelope_sha256.clone(), - coverage_store_file_identity: coverage.store_binding.store_file_identity.clone(), - runtime_coverage_route_envelope_digest: coverage - .runtime_coverage_route_envelope_sha256 - .clone(), - body_binding_sha256: basis.body_binding_sha256, - body_observation_id: acquisition.claim.body_observation_id.clone(), - body_generation: acquisition.claim.body_generation, - manifest_root_sha256: acquisition.claim.manifest_root_sha256.clone(), - claim_id: acquisition.claim.claim_id.clone(), - claim_epoch: acquisition.claim.claim_epoch, - plan_id: acquisition.claim.plan_id.clone(), - attempt_id: acquisition.attempt.attempt_id.clone(), - attempt_envelope_digest: envelope_digest(attempt_env), - recovery_receipt_id: acquisition.claim.recovery_receipt_id.clone(), - recovery_receipt_digest: acquisition.claim.recovery_receipt_digest.clone(), - observed_at_utc: observed_at.to_rfc3339(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - validate_workspace_coverage_sight_closing_authority( - runtime_store, - coverage, - &entry.workspace_id, - &entry.body_binding_sha256, - &entry.body_observation_id, - entry.body_generation, - &entry.manifest_root_sha256, - )?; - validate_claim_sight_shape(&entry, false)?; - entry.provider_signature = provider - .sign(&signed_sight_statement( - COVERAGE_CLAIM_SIGHT_DOMAIN, - &entry, - )?) - .to_bytes() - .to_vec(); - validate_claim_sight_shape(&entry, true)?; - let backing = SingleFileMessagePackBackingStore::new(local_verse_store); - let node = open_epiphany_cultmesh_node(local_verse_store, runtime_id.to_string())?; - let key = claim_sight_key( - runtime_id, - entry.body_generation, - &entry.body_observation_id, - ); - let opening = backing.pull_all()?; - if let Some(prior_env) = opening - .iter() - .find(|env| env.r#type == WORKSPACE_COVERAGE_CLAIM_SIGHT_TYPE && env.key == key) - { - let prior: WorkspaceCoverageClaimSightEntry = rmp_serde::from_slice(&prior_env.payload)?; - authenticate_workspace_coverage_claim_sight_entry(&prior)?; - if entry.claim_epoch < prior.claim_epoch - || (entry.claim_epoch == prior.claim_epoch && entry.claim_id != prior.claim_id) - { - bail!("workspace coverage claim sight cannot regress or fork its epoch"); - } - } - replace_latest_sight( - node.cache(), - &backing, - WORKSPACE_COVERAGE_CLAIM_SIGHT_TYPE, - &key, - &entry, - &opening, - )?; - Ok(entry) -} - -fn authenticate_workspace_coverage_claim_sight_entry( - entry: &WorkspaceCoverageClaimSightEntry, -) -> Result<()> { - validate_claim_sight_shape(entry, true)?; - let key: [u8; 32] = entry - .provider_public_key - .clone() - .try_into() - .map_err(|_| anyhow!("claim sight provider key length is invalid"))?; - let signature = Signature::from_slice(&entry.provider_signature)?; - let mut unsigned = entry.clone(); - unsigned.provider_signature.clear(); - VerifyingKey::from_bytes(&key)? - .verify( - &signed_sight_statement(COVERAGE_CLAIM_SIGHT_DOMAIN, &unsigned)?, - &signature, - ) - .map_err(|_| anyhow!("workspace coverage claim sight signature verification failed"))?; - Ok(()) -} - -pub fn authenticate_current_workspace_coverage_claim_sight( - local_verse_store: impl AsRef, - runtime_store: impl AsRef, - runtime_id: &str, - trusted_host: &HostIncarnationIdentityEntry, -) -> Result> { - authenticate_workspace_coverage_claim_sight( - local_verse_store, - runtime_store, - runtime_id, - trusted_host, - true, - ) -} - -pub fn authenticate_recovery_workspace_coverage_claim_sight( - local_verse_store: impl AsRef, - runtime_store: impl AsRef, - runtime_id: &str, - trusted_host: &HostIncarnationIdentityEntry, -) -> Result> { - authenticate_workspace_coverage_claim_sight( - local_verse_store, - runtime_store, - runtime_id, - trusted_host, - false, - ) -} - -fn authenticate_workspace_coverage_claim_sight( - local_verse_store: impl AsRef, - runtime_store: impl AsRef, - runtime_id: &str, - trusted_host: &HostIncarnationIdentityEntry, - require_current_policy: bool, -) -> Result> { - let runtime_store = runtime_store.as_ref(); - let basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let route = crate::runtime_workspace_coverage_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no workspace coverage route"))?; - let runtime_opening = SingleFileMessagePackBackingStore::new(runtime_store).pull_all()?; - let route_env = runtime_opening - .iter() - .find(|env| { - env.r#type == crate::RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE - && env.key == crate::RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY - }) - .ok_or_else(|| anyhow!("runtime workspace coverage route envelope is absent"))?; - let node = open_epiphany_cultmesh_node(local_verse_store.as_ref(), runtime_id.to_string())?; - let Some(env) = node - .cache() - .get_envelope::(&claim_sight_key( - runtime_id, - basis.generation, - &basis.observation_id, - ))? - else { - return Ok(None); - }; - if env.r#type != WORKSPACE_COVERAGE_CLAIM_SIGHT_TYPE { - bail!("claim sight key has alien type"); - } - let entry: WorkspaceCoverageClaimSightEntry = rmp_serde::from_slice(&env.payload)?; - authenticate_workspace_coverage_claim_sight_entry(&entry)?; - let (launch, digest) = if require_current_policy { - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id, - &entry.launch_id, - trusted_host, - )? - } else { - let launch = authenticate_historical_workspace_coverage_managed_process_launch( - local_verse_store.as_ref(), - runtime_id, - &entry.launch_id, - trusted_host, - )?; - let envelope = node - .cache() - .get_envelope::(&launch_key( - &entry.launch_id, - ))? - .ok_or_else(|| anyhow!("historical claim launch envelope disappeared"))?; - (launch, envelope_digest(&envelope)) - }; - if entry.runtime_id != runtime_id - || entry.launch_envelope_digest != digest - || entry.provider_incarnation_id != launch.provider_incarnation_id - || entry.provider_public_key != launch.provider_public_key - || entry.workspace_id != basis.workspace_id - || entry.body_binding_sha256 != basis.body_binding_sha256 - || entry.body_observation_id != basis.observation_id - || entry.body_generation != basis.generation - || entry.manifest_root_sha256 != basis.manifest_root_sha256 - || entry.coverage_store_binding_id != route.binding_id - || entry.coverage_store_file_identity != route.store_file_identity - || entry.runtime_coverage_route_envelope_digest - != format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(route_env)?)) - { - bail!("claim sight disagrees with authenticated launch"); - } - Ok(Some(entry)) -} - -fn recovery_directive_key(runtime_id: &str, replacement_launch_id: &str) -> String { - format!( - "epiphany-local/workspace-coverage/recovery-directive/{runtime_id}/{replacement_launch_id}" - ) -} - -fn recovery_directive_statement( - entry: &WorkspaceCoverageRecoveryDirectiveEntry, -) -> Result> { - let mut unsigned = entry.clone(); - unsigned.host_signature.clear(); - Ok(rmp_serde::to_vec_named(&unsigned)?) -} - -pub fn write_workspace_coverage_recovery_directive( - local_verse_store: impl AsRef, - runtime_store: impl AsRef, - runtime_id: &str, - claim_sight: &WorkspaceCoverageClaimSightEntry, - replacement_launch_id: &str, - replacement_ready_heartbeat_id: &str, - host: &HostIdentitySigner, -) -> Result { - let local_verse_store = local_verse_store.as_ref(); - let runtime_store = runtime_store.as_ref(); - let authenticated = authenticate_recovery_workspace_coverage_claim_sight( - local_verse_store, - runtime_store, - runtime_id, - host.entry(), - )? - .ok_or_else(|| anyhow!("workspace coverage recovery claim sight is absent"))?; - if &authenticated != claim_sight { - bail!("workspace coverage recovery claim sight moved"); - } - let node = open_epiphany_cultmesh_node(local_verse_store, runtime_id.to_string())?; - let directive_key = recovery_directive_key(runtime_id, replacement_launch_id); - if node - .cache() - .get_envelope::(&directive_key)? - .is_some() - { - let existing = authenticate_workspace_coverage_recovery_directive( - local_verse_store, - runtime_store, - runtime_id, - replacement_launch_id, - host.entry(), - )? - .ok_or_else(|| anyhow!("existing recovery directive belongs to a stale Body"))?; - if existing.old_claim_id != claim_sight.claim_id - || existing.old_claim_epoch != claim_sight.claim_epoch - || existing.old_plan_id != claim_sight.plan_id - || existing.old_launch_id != claim_sight.launch_id - || existing.workspace_id != claim_sight.workspace_id - || existing.body_binding_sha256 != claim_sight.body_binding_sha256 - || existing.body_observation_id != claim_sight.body_observation_id - || existing.body_generation != claim_sight.body_generation - || existing.manifest_root_sha256 != claim_sight.manifest_root_sha256 - || existing.coverage_store_binding_id != claim_sight.coverage_store_binding_id - || existing.coverage_store_binding_envelope_digest - != claim_sight.coverage_store_binding_envelope_digest - || existing.coverage_store_file_identity != claim_sight.coverage_store_file_identity - || existing.runtime_coverage_route_envelope_digest - != claim_sight.runtime_coverage_route_envelope_digest - { - bail!( - "recovery directive replacement identity already belongs to another claim lineage" - ); - } - return Ok(existing); - } - let claim_env = node - .cache() - .get_envelope::(&claim_sight_key( - runtime_id, - claim_sight.body_generation, - &claim_sight.body_observation_id, - ))? - .ok_or_else(|| anyhow!("workspace coverage recovery claim sight envelope is absent"))?; - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - local_verse_store, - runtime_id.to_string(), - &claim_sight.launch_id, - host.entry(), - )?; - let (replacement, replacement_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - runtime_id, - replacement_launch_id, - host.entry(), - )?; - authenticate_workspace_coverage_replacement_lineage( - local_verse_store, - runtime_id, - &claim_sight.launch_id, - replacement_launch_id, - host.entry(), - )?; - let (ready, ready_digest) = - authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest( - local_verse_store, - runtime_id, - replacement_ready_heartbeat_id, - host.entry(), - )?; - if ready.launch_id != replacement.launch_id || ready.status != "ready" { - bail!("workspace coverage recovery directive evidence is not an exact ready replacement"); - } - let mut entry = WorkspaceCoverageRecoveryDirectiveEntry { - schema_version: WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_SCHEMA_VERSION.into(), - directive_id: uuid::Uuid::new_v4().to_string(), - runtime_id: runtime_id.into(), - old_claim_id: claim_sight.claim_id.clone(), - old_launch_id: claim_sight.launch_id.clone(), - replacement_launch_id: replacement.launch_id, - replacement_ready_heartbeat_id: ready.heartbeat_id, - termination_id: termination.termination_id, - claim_sight_envelope_digest: envelope_digest(&claim_env), - old_claim_epoch: claim_sight.claim_epoch, - old_plan_id: claim_sight.plan_id.clone(), - termination_envelope_digest: termination_digest, - replacement_launch_envelope_digest: replacement_digest, - replacement_ready_heartbeat_envelope_digest: ready_digest, - workspace_id: claim_sight.workspace_id.clone(), - body_binding_sha256: claim_sight.body_binding_sha256.clone(), - body_observation_id: claim_sight.body_observation_id.clone(), - body_generation: claim_sight.body_generation, - manifest_root_sha256: claim_sight.manifest_root_sha256.clone(), - coverage_store_binding_id: claim_sight.coverage_store_binding_id.clone(), - coverage_store_binding_envelope_digest: claim_sight - .coverage_store_binding_envelope_digest - .clone(), - coverage_store_file_identity: claim_sight.coverage_store_file_identity.clone(), - runtime_coverage_route_envelope_digest: claim_sight - .runtime_coverage_route_envelope_digest - .clone(), - issued_at_utc: chrono::Utc::now().to_rfc3339(), - host_identity_id: host.entry().identity_id.clone(), - host_identity_record_digest: workspace_coverage_host_identity_record_digest(host.entry())?, - host_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - entry.host_signature = host - .sign( - HOST_RECOVERY_DIRECTIVE_PURPOSE, - &recovery_directive_statement(&entry)?, - )? - .signature; - let backing = SingleFileMessagePackBackingStore::new(local_verse_store); - let opening = backing.pull_all()?; - replace_latest_sight( - node.cache(), - &backing, - WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_TYPE, - &directive_key, - &entry, - &opening, - )?; - Ok(entry) -} - -pub fn authenticate_workspace_coverage_recovery_directive( - local_verse_store: impl AsRef, - runtime_store: impl AsRef, - runtime_id: &str, - replacement_launch_id: &str, - trusted_host: &HostIncarnationIdentityEntry, -) -> Result> { - let node = open_epiphany_cultmesh_node(local_verse_store.as_ref(), runtime_id.to_string())?; - let Some(env) = node - .cache() - .get_envelope::(&recovery_directive_key( - runtime_id, - replacement_launch_id, - ))? - else { - return Ok(None); - }; - let entry: WorkspaceCoverageRecoveryDirectiveEntry = rmp_serde::from_slice(&env.payload)?; - if entry.schema_version != WORKSPACE_COVERAGE_RECOVERY_DIRECTIVE_SCHEMA_VERSION - || entry.runtime_id != runtime_id - || entry.replacement_launch_id != replacement_launch_id - || entry.host_identity_id != trusted_host.identity_id - || entry.host_identity_record_digest - != workspace_coverage_host_identity_record_digest(trusted_host)? - || entry.signature_algorithm != "ed25519" - { - bail!("workspace coverage recovery directive identity is invalid"); - } - verify_host_identity_signature( - trusted_host, - HOST_RECOVERY_DIRECTIVE_PURPOSE, - &recovery_directive_statement(&entry)?, - &HostIdentitySignature { - identity_id: entry.host_identity_id.clone(), - signature: entry.host_signature.clone(), - }, - )?; - let basis = crate::load_current_runtime_repository_body_basis(runtime_store.as_ref())?; - if entry.body_observation_id != basis.observation_id - || entry.body_generation != basis.generation - || entry.manifest_root_sha256 != basis.manifest_root_sha256 - || entry.body_binding_sha256 != basis.body_binding_sha256 - || entry.workspace_id != basis.workspace_id - { - // A directive is authority only for its exact Body generation. Keeping - // the immutable document is useful evidence; treating it as current - // pressure after Body advances would strand the replacement process. - return Ok(None); - } - let claim_node = - open_epiphany_cultmesh_node(local_verse_store.as_ref(), runtime_id.to_string())?; - let claim_env = claim_node - .cache() - .get_envelope::(&claim_sight_key( - runtime_id, - basis.generation, - &basis.observation_id, - ))? - .ok_or_else(|| anyhow!("recovery directive claim sight is absent"))?; - let claim: WorkspaceCoverageClaimSightEntry = rmp_serde::from_slice(&claim_env.payload)?; - authenticate_workspace_coverage_claim_sight_entry(&claim)?; - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id.to_string(), - &entry.old_launch_id, - trusted_host, - )?; - let (_, replacement_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id, - &entry.replacement_launch_id, - trusted_host, - )?; - let (_, ready_digest) = - authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id, - &entry.replacement_ready_heartbeat_id, - trusted_host, - )?; - if entry.claim_sight_envelope_digest != envelope_digest(&claim_env) - || entry.old_claim_id != claim.claim_id - || entry.old_claim_epoch != claim.claim_epoch - || entry.old_plan_id != claim.plan_id - || entry.old_launch_id != claim.launch_id - || entry.termination_id != termination.termination_id - || entry.termination_envelope_digest != termination_digest - || entry.replacement_launch_envelope_digest != replacement_digest - || entry.replacement_ready_heartbeat_envelope_digest != ready_digest - || entry.workspace_id != claim.workspace_id - || entry.body_binding_sha256 != claim.body_binding_sha256 - || entry.body_observation_id != claim.body_observation_id - || entry.body_generation != claim.body_generation - || entry.manifest_root_sha256 != claim.manifest_root_sha256 - || entry.coverage_store_binding_id != claim.coverage_store_binding_id - || entry.coverage_store_binding_envelope_digest - != claim.coverage_store_binding_envelope_digest - || entry.coverage_store_file_identity != claim.coverage_store_file_identity - || entry.runtime_coverage_route_envelope_digest - != claim.runtime_coverage_route_envelope_digest - { - bail!("workspace coverage recovery directive evidence moved or was substituted"); - } - Ok(Some(entry)) -} - -fn advancement_sight_key(launch_id: &str, claim_id: &str) -> String { - format!("epiphany-local/workspace-coverage/advancement-sight/{launch_id}/{claim_id}") -} - -fn terminal_sight_key(runtime_id: &str, body_generation: u64, body_observation_id: &str) -> String { - format!( - "epiphany-local/workspace-coverage/terminal-sight/{runtime_id}/{body_generation}/{body_observation_id}" - ) -} - -fn signed_sight_statement(domain: &[u8], unsigned: &T) -> Result> { - let mut statement = domain.to_vec(); - statement.extend(rmp_serde::to_vec_named(unsigned)?); - Ok(statement) -} - -pub(crate) fn sign_workspace_coverage_advancement_sight( - entry: &mut WorkspaceCoverageAdvancementSightEntry, - provider: &SigningKey, -) -> Result<()> { - entry.provider_signature.clear(); - validate_advancement_sight_shape(entry, false)?; - entry.provider_signature = provider - .sign(&signed_sight_statement( - COVERAGE_ADVANCEMENT_SIGHT_DOMAIN, - entry, - )?) - .to_bytes() - .to_vec(); - Ok(()) -} - -pub(crate) fn sign_workspace_coverage_terminal_sight( - entry: &mut WorkspaceCoverageTerminalSightEntry, - provider: &SigningKey, -) -> Result<()> { - entry.provider_signature.clear(); - validate_terminal_sight_shape(entry, false)?; - entry.provider_signature = provider - .sign(&signed_sight_statement( - COVERAGE_TERMINAL_SIGHT_DOMAIN, - entry, - )?) - .to_bytes() - .to_vec(); - Ok(()) -} - -pub(crate) fn write_workspace_coverage_advancement_sight( - local_verse_store: impl AsRef, - runtime_id: &str, - entry: WorkspaceCoverageAdvancementSightEntry, -) -> Result { - validate_advancement_sight_shape(&entry, true)?; - if entry.runtime_id != runtime_id { - bail!("workspace coverage advancement sight runtime argument disagrees"); - } - let backing = SingleFileMessagePackBackingStore::new(local_verse_store.as_ref()); - let node = open_epiphany_cultmesh_node(local_verse_store.as_ref(), runtime_id.to_string())?; - let key = advancement_sight_key(&entry.launch_id, &entry.claim_id); - let opening = backing.pull_all()?; - if let Some(prior) = opening.iter().find(|envelope| { - envelope.r#type == WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_TYPE && envelope.key == key - }) { - let prior: WorkspaceCoverageAdvancementSightEntry = rmp_serde::from_slice(&prior.payload)?; - validate_advancement_sight_shape(&prior, true)?; - let mut unsigned = prior.clone(); - unsigned.provider_signature.clear(); - verify_sight_signature( - COVERAGE_ADVANCEMENT_SIGHT_DOMAIN, - &unsigned, - &prior.provider_public_key, - &prior.provider_signature, - )?; - if entry.sequence <= prior.sequence - || entry.completed_units < prior.completed_units - || entry.total_units != prior.total_units - || entry.body_observation_id != prior.body_observation_id - || entry.body_generation != prior.body_generation - || entry.plan_id != prior.plan_id - || entry.launch_envelope_digest != prior.launch_envelope_digest - || entry.provider_incarnation_id != prior.provider_incarnation_id - || entry.provider_public_key != prior.provider_public_key - || entry.coverage_store_binding_id != prior.coverage_store_binding_id - || entry.coverage_store_binding_envelope_digest - != prior.coverage_store_binding_envelope_digest - || entry.coverage_store_file_identity != prior.coverage_store_file_identity - || entry.runtime_coverage_route_envelope_digest - != prior.runtime_coverage_route_envelope_digest - || entry.body_binding_sha256 != prior.body_binding_sha256 - || entry.manifest_root_sha256 != prior.manifest_root_sha256 - { - bail!("workspace coverage advancement sight cannot regress or substitute its basis"); - } - } - replace_latest_sight( - node.cache(), - &backing, - WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_TYPE, - &key, - &entry, - &opening, - )?; - Ok(entry) -} - -pub(crate) fn write_workspace_coverage_terminal_sight( - local_verse_store: impl AsRef, - runtime_id: &str, - entry: WorkspaceCoverageTerminalSightEntry, -) -> Result { - validate_terminal_sight_shape(&entry, true)?; - if entry.runtime_id != runtime_id { - bail!("workspace coverage terminal sight runtime argument disagrees"); - } - let backing = SingleFileMessagePackBackingStore::new(local_verse_store.as_ref()); - let node = open_epiphany_cultmesh_node(local_verse_store.as_ref(), runtime_id.to_string())?; - let key = terminal_sight_key( - runtime_id, - entry.body_generation, - &entry.body_observation_id, - ); - let opening = backing.pull_all()?; - if let Some(prior) = opening.iter().find(|envelope| { - envelope.r#type == WORKSPACE_COVERAGE_TERMINAL_SIGHT_TYPE && envelope.key == key - }) { - let prior: WorkspaceCoverageTerminalSightEntry = rmp_serde::from_slice(&prior.payload)?; - validate_terminal_sight_shape(&prior, true)?; - let mut unsigned = prior.clone(); - unsigned.provider_signature.clear(); - verify_sight_signature( - COVERAGE_TERMINAL_SIGHT_DOMAIN, - &unsigned, - &prior.provider_public_key, - &prior.provider_signature, - )?; - if prior == entry { - return Ok(entry); - } - bail!("workspace coverage terminal sight is immutable for its exact Body basis"); - } - replace_latest_sight( - node.cache(), - &backing, - WORKSPACE_COVERAGE_TERMINAL_SIGHT_TYPE, - &key, - &entry, - &opening, - )?; - Ok(entry) -} - -/// Publishes operator sight only after the owned coverage store proves a -/// current durable checkpoint/progress join. The returned document grants no -/// authority over that store. -#[allow(clippy::too_many_arguments)] -pub(crate) fn publish_workspace_coverage_advancement_sight( - local_verse_store: &Path, - runtime_store: &Path, - coverage: &crate::WorkspaceCoverageAuthority, - runtime_id: &str, - launch_id: &str, - trusted_host: &HostIncarnationIdentityEntry, - provider: &SigningKey, - observed_at: chrono::DateTime, - no_advance_lease: chrono::Duration, -) -> Result { - let advancing = crate::authenticate_current_workspace_coverage_advancement( - Path::new(&coverage.runtime_body_route.body_store_path), - &coverage.store, - local_verse_store, - runtime_id, - launch_id, - trusted_host, - observed_at, - no_advance_lease, - )? - .ok_or_else(|| anyhow!("owned workspace coverage has no current advancing authority"))?; - let opening = coverage.store.pull_all()?; - let progress_env = opening - .iter() - .find(|env| { - env.r#type == crate::WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE && { - rmp_serde::from_slice::( - &env.payload, - ) - .is_ok_and(|progress| progress.progress_id == advancing.progress_id) - } - }) - .ok_or_else(|| anyhow!("advancement sight progress envelope is absent"))?; - let progress: crate::WorkspaceCoverageProjectionProgressEntry = - rmp_serde::from_slice(&progress_env.payload)?; - let checkpoint_env = opening.iter().find(|env| env.r#type == crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE && { - rmp_serde::from_slice::(&env.payload) - .is_ok_and(|checkpoint| checkpoint.checkpoint_id == advancing.checkpoint_id) - }).ok_or_else(|| anyhow!("advancement sight checkpoint envelope is absent"))?; - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - runtime_id, - launch_id, - trusted_host, - )?; - let basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let mut entry = WorkspaceCoverageAdvancementSightEntry { - schema_version: WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION.into(), - runtime_id: runtime_id.into(), - workspace_id: basis.workspace_id, - launch_id: launch_id.into(), - launch_envelope_digest: launch_digest, - provider_incarnation_id: launch.provider_incarnation_id, - provider_public_key: launch.provider_public_key, - coverage_store_binding_id: coverage.store_binding.binding_id.clone(), - coverage_store_binding_envelope_digest: coverage.store_binding_envelope_sha256.clone(), - coverage_store_file_identity: coverage.store_binding.store_file_identity.clone(), - runtime_coverage_route_envelope_digest: coverage - .runtime_coverage_route_envelope_sha256 - .clone(), - body_binding_sha256: basis.body_binding_sha256, - body_observation_id: basis.observation_id, - body_generation: basis.generation, - manifest_root_sha256: basis.manifest_root_sha256, - claim_id: advancing.claim_id, - claim_epoch: advancing.claim_epoch, - plan_id: advancing.plan_id, - progress_id: advancing.progress_id, - progress_envelope_digest: envelope_digest(progress_env), - checkpoint_id: advancing.checkpoint_id, - checkpoint_envelope_digest: envelope_digest(checkpoint_env), - sequence: progress.sequence, - status: "warming".into(), - completed_units: advancing.completed_units, - total_units: advancing.total_units, - last_advanced_at_utc: advancing.last_advanced_at_utc, - observed_at_utc: observed_at.to_rfc3339(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - validate_workspace_coverage_sight_closing_authority( - runtime_store, - coverage, - &entry.workspace_id, - &entry.body_binding_sha256, - &entry.body_observation_id, - entry.body_generation, - &entry.manifest_root_sha256, - )?; - sign_workspace_coverage_advancement_sight(&mut entry, provider)?; - write_workspace_coverage_advancement_sight(local_verse_store, runtime_id, entry) -} - -pub(crate) fn publish_workspace_coverage_terminal_sight( - local_verse_store: &Path, - runtime_store: &Path, - coverage: &crate::WorkspaceCoverageAuthority, - runtime_id: &str, - launch_id: &str, - trusted_host: &HostIncarnationIdentityEntry, - provider: &SigningKey, - observed_at: chrono::DateTime, -) -> Result { - let terminal = crate::workspace_coverage_projector::authenticate_current_workspace_coverage_terminal_authority_with_store( - runtime_store, &coverage.store, - )?.ok_or_else(|| anyhow!("owned workspace coverage has no current terminal authority"))?; - if let Some(existing) = authenticate_current_workspace_coverage_terminal_sight( - runtime_store, - local_verse_store, - runtime_id, - trusted_host, - )? { - if existing.launch_id == terminal.managed_process_launch_id - && existing.claim_id == terminal.claim_id - && existing.claim_epoch == terminal.claim_epoch - && existing.plan_id == terminal.plan_id - && existing.receipt_id == terminal.receipt_id - { - return Ok(existing); - } - bail!("current terminal sight disagrees with owned terminal authority"); - } - if terminal.managed_process_launch_id != launch_id { - bail!("terminal sight launch disagrees with terminal coverage authority"); - } - let opening = coverage.store.pull_all()?; - let receipt_env = opening - .iter() - .find(|env| { - env.r#type == "gamecult.epiphany.workspace_coverage_receipt" && { - rmp_serde::from_slice::< - crate::workspace_retrieval_coverage::WorkspaceCoverageReceipt, - >(&env.payload) - .is_ok_and(|receipt| receipt.receipt_id == terminal.receipt_id) - } - }) - .ok_or_else(|| anyhow!("terminal sight receipt envelope is absent"))?; - let head_env = opening - .iter() - .find(|env| { - env.r#type == "gamecult.epiphany.workspace_coverage_head" && env.key == "current" - }) - .ok_or_else(|| anyhow!("terminal sight head envelope is absent"))?; - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - runtime_id, - launch_id, - trusted_host, - )?; - let basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let mut entry = WorkspaceCoverageTerminalSightEntry { - schema_version: WORKSPACE_COVERAGE_TERMINAL_SIGHT_SCHEMA_VERSION.into(), - runtime_id: runtime_id.into(), - workspace_id: basis.workspace_id, - launch_id: launch_id.into(), - launch_envelope_digest: launch_digest, - provider_incarnation_id: launch.provider_incarnation_id, - provider_public_key: launch.provider_public_key, - coverage_store_binding_id: coverage.store_binding.binding_id.clone(), - coverage_store_binding_envelope_digest: coverage.store_binding_envelope_sha256.clone(), - coverage_store_file_identity: coverage.store_binding.store_file_identity.clone(), - runtime_coverage_route_envelope_digest: coverage - .runtime_coverage_route_envelope_sha256 - .clone(), - body_binding_sha256: basis.body_binding_sha256, - body_observation_id: terminal.body_observation_id, - body_generation: terminal.body_generation, - manifest_root_sha256: basis.manifest_root_sha256, - claim_id: terminal.claim_id, - claim_epoch: terminal.claim_epoch, - plan_id: terminal.plan_id, - receipt_id: terminal.receipt_id, - receipt_envelope_digest: envelope_digest(receipt_env), - head_id: "current".into(), - head_envelope_digest: envelope_digest(head_env), - sequence: terminal.claim_epoch, - status: "succeeded".into(), - observed_at_utc: observed_at.to_rfc3339(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - validate_workspace_coverage_sight_closing_authority( - runtime_store, - coverage, - &entry.workspace_id, - &entry.body_binding_sha256, - &entry.body_observation_id, - entry.body_generation, - &entry.manifest_root_sha256, - )?; - sign_workspace_coverage_terminal_sight(&mut entry, provider)?; - write_workspace_coverage_terminal_sight(local_verse_store, runtime_id, entry) -} - -pub(crate) fn validate_workspace_coverage_sight_closing_authority( - runtime_store: &Path, - coverage: &crate::WorkspaceCoverageAuthority, - expected_workspace_id: &str, - expected_body_binding_sha256: &str, - expected_body_observation_id: &str, - expected_body_generation: u64, - expected_manifest_root_sha256: &str, -) -> Result<()> { - let closing_basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let closing_route = crate::runtime_workspace_coverage_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime lost workspace coverage route before sight publication"))?; - if closing_basis.workspace_id != expected_workspace_id - || closing_basis.body_binding_sha256 != expected_body_binding_sha256 - || closing_basis.observation_id != expected_body_observation_id - || closing_basis.generation != expected_body_generation - || closing_basis.manifest_root_sha256 != expected_manifest_root_sha256 - || closing_route != coverage.runtime_coverage_route - { - bail!("Repository Body or coverage route moved before sight publication"); - } - Ok(()) -} - -fn replace_latest_sight( - cache: &cultcache_rs::CultCache, - backing: &SingleFileMessagePackBackingStore, - ty: &str, - key: &str, - entry: &T, - opening: &[CultCacheEnvelope], -) -> Result<()> { - let expected = opening - .iter() - .filter(|envelope| envelope.r#type == ty && envelope.key == key) - .cloned() - .collect::>(); - if expected.len() > 1 { - bail!("workspace coverage sight latest identity is duplicated"); - } - let replacement = cache.prepare_entry(key, entry)?.0; - if !backing.compare_and_swap_batch(&expected, vec![replacement])? { - bail!("workspace coverage sight lost exact latest compare-and-swap"); - } - Ok(()) -} - -pub fn authenticate_current_workspace_coverage_advancement_sight( - runtime_store: impl AsRef, - local_verse_store: impl AsRef, - runtime_id: &str, - launch_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result> { - let basis = crate::load_current_runtime_repository_body_basis(runtime_store.as_ref())?; - let local = SingleFileMessagePackBackingStore::new(local_verse_store.as_ref()).pull_all()?; - let prefix = format!("epiphany-local/workspace-coverage/advancement-sight/{launch_id}/"); - let mut matches = Vec::new(); - for envelope in local.iter().filter(|envelope| { - envelope.r#type == WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_TYPE - && envelope.key.starts_with(&prefix) - }) { - let entry: WorkspaceCoverageAdvancementSightEntry = - rmp_serde::from_slice(&envelope.payload)?; - validate_advancement_sight_shape(&entry, true)?; - if envelope.key != advancement_sight_key(&entry.launch_id, &entry.claim_id) { - bail!("workspace coverage advancement sight key disagrees with signed identity"); - } - if entry.body_observation_id == basis.observation_id - && entry.body_generation == basis.generation - { - matches.push((envelope, entry)); - } - } - if matches.len() > 1 { - bail!("workspace coverage launch has multiple current advancement sights"); - } - let Some((_, entry)) = matches.first() else { - return Ok(None); - }; - let entry = entry.clone(); - authenticate_advancement_sight( - &entry, - runtime_store.as_ref(), - local_verse_store.as_ref(), - runtime_id, - launch_id, - host, - )?; - Ok(Some(entry)) -} - -pub fn authenticate_current_workspace_coverage_terminal_sight( - runtime_store: impl AsRef, - local_verse_store: impl AsRef, - runtime_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result> { - let basis = crate::load_current_runtime_repository_body_basis(runtime_store.as_ref())?; - let key = terminal_sight_key(runtime_id, basis.generation, &basis.observation_id); - let local = SingleFileMessagePackBackingStore::new(local_verse_store.as_ref()).pull_all()?; - let matches = local - .iter() - .filter(|envelope| { - envelope.r#type == WORKSPACE_COVERAGE_TERMINAL_SIGHT_TYPE && envelope.key == key - }) - .collect::>(); - if matches.len() > 1 { - bail!("workspace coverage terminal sight identity is duplicated"); - } - let Some(envelope) = matches.first() else { - return Ok(None); - }; - let entry: WorkspaceCoverageTerminalSightEntry = rmp_serde::from_slice(&envelope.payload)?; - authenticate_terminal_sight( - &entry, - runtime_store.as_ref(), - local_verse_store.as_ref(), - runtime_id, - host, - )?; - Ok(Some(entry)) -} - -fn authenticate_advancement_sight( - entry: &WorkspaceCoverageAdvancementSightEntry, - runtime_store: &Path, - local_verse_store: &Path, - runtime_id: &str, - launch_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result<()> { - validate_advancement_sight_shape(entry, true)?; - if entry.runtime_id != runtime_id || entry.launch_id != launch_id { - bail!("workspace coverage advancement sight identity disagrees"); - } - authenticate_sight_common( - WorkspaceCoverageSightLaunchAuthority::Current, - runtime_store, - local_verse_store, - runtime_id, - host, - &entry.launch_id, - &entry.launch_envelope_digest, - &entry.provider_incarnation_id, - &entry.provider_public_key, - &entry.workspace_id, - &entry.coverage_store_binding_id, - &entry.coverage_store_binding_envelope_digest, - &entry.coverage_store_file_identity, - &entry.runtime_coverage_route_envelope_digest, - &entry.body_binding_sha256, - &entry.body_observation_id, - entry.body_generation, - &entry.manifest_root_sha256, - )?; - let mut unsigned = entry.clone(); - unsigned.provider_signature.clear(); - verify_sight_signature( - COVERAGE_ADVANCEMENT_SIGHT_DOMAIN, - &unsigned, - &entry.provider_public_key, - &entry.provider_signature, - ) -} - -fn authenticate_terminal_sight( - entry: &WorkspaceCoverageTerminalSightEntry, - runtime_store: &Path, - local_verse_store: &Path, - runtime_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result<()> { - validate_terminal_sight_shape(entry, true)?; - if entry.runtime_id != runtime_id { - bail!("workspace coverage terminal sight identity disagrees"); - } - authenticate_sight_common( - WorkspaceCoverageSightLaunchAuthority::HistoricalTerminal, - runtime_store, - local_verse_store, - runtime_id, - host, - &entry.launch_id, - &entry.launch_envelope_digest, - &entry.provider_incarnation_id, - &entry.provider_public_key, - &entry.workspace_id, - &entry.coverage_store_binding_id, - &entry.coverage_store_binding_envelope_digest, - &entry.coverage_store_file_identity, - &entry.runtime_coverage_route_envelope_digest, - &entry.body_binding_sha256, - &entry.body_observation_id, - entry.body_generation, - &entry.manifest_root_sha256, - )?; - let mut unsigned = entry.clone(); - unsigned.provider_signature.clear(); - verify_sight_signature( - COVERAGE_TERMINAL_SIGHT_DOMAIN, - &unsigned, - &entry.provider_public_key, - &entry.provider_signature, - ) -} - -#[derive(Clone, Copy)] -enum WorkspaceCoverageSightLaunchAuthority { - Current, - HistoricalTerminal, -} - -#[allow(clippy::too_many_arguments)] -fn authenticate_sight_common( - launch_authority: WorkspaceCoverageSightLaunchAuthority, - runtime_store: &Path, - local_verse_store: &Path, - runtime_id: &str, - host: &HostIncarnationIdentityEntry, - launch_id: &str, - launch_digest: &str, - provider_incarnation_id: &str, - provider_public_key: &[u8], - workspace_id: &str, - binding_id: &str, - binding_envelope_digest: &str, - store_file_identity: &str, - runtime_route_digest: &str, - body_binding_sha256: &str, - body_observation_id: &str, - body_generation: u64, - manifest_root_sha256: &str, -) -> Result<()> { - let (launch, exact_launch_digest) = match launch_authority { - WorkspaceCoverageSightLaunchAuthority::Current => { - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - runtime_id, - launch_id, - host, - )? - } - WorkspaceCoverageSightLaunchAuthority::HistoricalTerminal => { - authenticate_historical_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - runtime_id, - launch_id, - host, - )? - } - }; - if exact_launch_digest != launch_digest - || launch.provider_incarnation_id != provider_incarnation_id - || launch.provider_public_key != provider_public_key - { - bail!("workspace coverage sight disagrees with exact managed launch"); - } - let basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - if basis.runtime_id != runtime_id - || basis.workspace_id != workspace_id - || basis.body_binding_sha256 != body_binding_sha256 - || basis.observation_id != body_observation_id - || basis.generation != body_generation - || basis.manifest_root_sha256 != manifest_root_sha256 - { - bail!("workspace coverage sight disagrees with current repository Body basis"); - } - let route = crate::runtime_workspace_coverage_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no workspace coverage store route"))?; - if route.binding_id != binding_id - || route.store_file_identity != store_file_identity - || route.runtime_id != runtime_id - || route.workspace_id != workspace_id - || route.body_binding_sha256 != body_binding_sha256 - { - bail!("workspace coverage sight disagrees with current coverage route"); - } - let opening = SingleFileMessagePackBackingStore::new(runtime_store).pull_all()?; - let route_env = opening - .iter() - .find(|env| { - env.r#type == crate::RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE - && env.key == crate::RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY - }) - .ok_or_else(|| anyhow!("runtime workspace coverage route envelope is absent"))?; - let exact_route_digest = format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(route_env)?)); - if exact_route_digest != runtime_route_digest { - bail!("workspace coverage sight route envelope was substituted"); - } - let body_route = crate::runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body route"))?; - let body_opening = - SingleFileMessagePackBackingStore::new(&body_route.body_store_path).pull_all()?; - let body_binding_env = body_opening - .iter() - .find(|env| env.r#type == crate::BODY_BINDING_TYPE && env.key == crate::BODY_BINDING_KEY) - .ok_or_else(|| anyhow!("repository Body binding envelope is absent"))?; - let body_binding: crate::RepositoryBodyBinding = - rmp_serde::from_slice(&body_binding_env.payload)?; - let local_binding = crate::WorkspaceCoverageStoreBinding { - schema_version: crate::WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION.into(), - binding_id: route.binding_id.clone(), - runtime_id: route.runtime_id.clone(), - swarm_id: route.swarm_id.clone(), - workspace_id: route.workspace_id.clone(), - store_file_identity: route.store_file_identity.clone(), - body_binding_sha256: route.body_binding_sha256.clone(), - repository_source_identity_sha256: body_binding.source_identity_sha256, - projection_scope: "workspace_coverage".into(), - storage_backend: "cultcache_redb_v0".into(), - created_at_utc: route.created_at_utc.clone(), - }; - let reconstructed = CultCacheEnvelope { - key: crate::WORKSPACE_COVERAGE_STORE_BINDING_KEY.into(), - r#type: crate::WORKSPACE_COVERAGE_STORE_BINDING_TYPE.into(), - payload: rmp_serde::to_vec(&local_binding)?, - stored_at: route.created_at_utc, - schema_id: Some(crate::WORKSPACE_COVERAGE_STORE_BINDING_TYPE.into()), - }; - let exact_binding_digest = format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(&reconstructed)?) - ); - if exact_binding_digest != binding_envelope_digest { - bail!("workspace coverage sight binding envelope was substituted"); - } - Ok(()) -} - -fn verify_sight_signature( - domain: &[u8], - entry: &T, - public_key: &[u8], - signature: &[u8], -) -> Result<()> { - let verifying = VerifyingKey::from_bytes( - public_key - .try_into() - .map_err(|_| anyhow!("workspace coverage sight public key must be 32 bytes"))?, - )?; - let signature = Signature::from_slice(signature)?; - verifying.verify(&signed_sight_statement(domain, entry)?, &signature)?; - Ok(()) -} - -fn validate_advancement_sight_shape( - entry: &WorkspaceCoverageAdvancementSightEntry, - signed: bool, -) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION - || entry.status != "warming" - || entry.sequence == 0 - || entry.claim_epoch == 0 - || entry.body_generation == 0 - || entry.completed_units == 0 - || entry.completed_units > entry.total_units - { - bail!("workspace coverage advancement sight shape is invalid"); - } - validate_sight_strings(&[ - &entry.runtime_id, - &entry.workspace_id, - &entry.launch_id, - &entry.launch_envelope_digest, - &entry.provider_incarnation_id, - &entry.coverage_store_binding_id, - &entry.coverage_store_binding_envelope_digest, - &entry.coverage_store_file_identity, - &entry.runtime_coverage_route_envelope_digest, - &entry.body_binding_sha256, - &entry.body_observation_id, - &entry.manifest_root_sha256, - &entry.claim_id, - &entry.plan_id, - &entry.progress_id, - &entry.progress_envelope_digest, - &entry.checkpoint_id, - &entry.checkpoint_envelope_digest, - &entry.last_advanced_at_utc, - &entry.observed_at_utc, - ])?; - DateTime::parse_from_rfc3339(&entry.last_advanced_at_utc)?; - DateTime::parse_from_rfc3339(&entry.observed_at_utc)?; - if entry.signature_algorithm != "ed25519" - || entry.provider_public_key.len() != 32 - || (signed && entry.provider_signature.len() != 64) - || (!signed && !entry.provider_signature.is_empty()) - { - bail!("workspace coverage advancement sight signature shape is invalid"); - } - Ok(()) -} - -fn validate_terminal_sight_shape( - entry: &WorkspaceCoverageTerminalSightEntry, - signed: bool, -) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_TERMINAL_SIGHT_SCHEMA_VERSION - || entry.status != "succeeded" - || entry.sequence == 0 - || entry.claim_epoch == 0 - || entry.body_generation == 0 - || entry.head_id != "current" - { - bail!("workspace coverage terminal sight shape is invalid"); - } - validate_sight_strings(&[ - &entry.runtime_id, - &entry.workspace_id, - &entry.launch_id, - &entry.launch_envelope_digest, - &entry.provider_incarnation_id, - &entry.coverage_store_binding_id, - &entry.coverage_store_binding_envelope_digest, - &entry.coverage_store_file_identity, - &entry.runtime_coverage_route_envelope_digest, - &entry.body_binding_sha256, - &entry.body_observation_id, - &entry.manifest_root_sha256, - &entry.claim_id, - &entry.plan_id, - &entry.receipt_id, - &entry.receipt_envelope_digest, - &entry.head_envelope_digest, - &entry.observed_at_utc, - ])?; - DateTime::parse_from_rfc3339(&entry.observed_at_utc)?; - if entry.signature_algorithm != "ed25519" - || entry.provider_public_key.len() != 32 - || (signed && entry.provider_signature.len() != 64) - || (!signed && !entry.provider_signature.is_empty()) - { - bail!("workspace coverage terminal sight signature shape is invalid"); - } - Ok(()) -} - -fn validate_sight_strings(values: &[&str]) -> Result<()> { - if values.iter().any(|value| value.trim().is_empty()) { - bail!("workspace coverage sight has an empty identity or digest"); - } - Ok(()) -} -fn validate_digest(name: &str, value: &str) -> Result<()> { - if value.len() != 71 - || !value.starts_with("sha256-") - || !value[7..].bytes().all(|byte| byte.is_ascii_hexdigit()) - { - bail!("workspace coverage {name} digest must be sha256 plus 64 hex digits"); - } - Ok(()) -} -fn validate_absolute_path(value: &str) -> Result<()> { - let path = Path::new(value); - if !path.is_absolute() { - bail!("workspace coverage process executable path must be absolute"); - } - Ok(()) -} -fn launch_key(id: &str) -> String { - format!("epiphany-local/workspace-coverage/managed-process-launch/{id}") -} -fn heartbeat_latest_key(launch_id: &str) -> String { - format!("{WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_LATEST_KEY}{launch_id}") -} -fn heartbeat_evidence_key(launch_id: &str, heartbeat_id: &str) -> String { - format!("epiphany-local/workspace-coverage/provider-heartbeat/{launch_id}/{heartbeat_id}") -} - -fn latest_heartbeat_envelope_by_id( - store_path: impl AsRef, - runtime_id: &str, - heartbeat_id: &str, -) -> Result> { - let _node = open_epiphany_cultmesh_node(store_path.as_ref(), runtime_id.to_string())?; - let opening = SingleFileMessagePackBackingStore::new(store_path.as_ref()).pull_all()?; - let matches = opening - .iter() - .filter(|envelope| { - envelope.r#type == WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_TYPE - && rmp_serde::from_slice::( - &envelope.payload, - ) - .is_ok_and(|heartbeat| { - heartbeat.runtime_id == runtime_id && heartbeat.heartbeat_id == heartbeat_id - }) - }) - .collect::>(); - let immutable = matches - .into_iter() - .filter(|envelope| { - !envelope - .key - .starts_with(WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_LATEST_KEY) - }) - .collect::>(); - if immutable.len() != 1 { - bail!("workspace coverage heartbeat immutable evidence is absent or duplicated"); - } - Ok(Some(immutable[0].clone())) -} -fn termination_key(launch_id: &str) -> String { - format!("epiphany-local/workspace-coverage/process-termination/{launch_id}") -} -fn process_evidence_head_key(launch_id: &str) -> String { - format!("epiphany-local/workspace-coverage/process-evidence-head/{launch_id}") -} - -fn validate_process_evidence_head( - head: &WorkspaceCoverageProcessEvidenceHead, - launch_id: &str, -) -> Result<()> { - if head.schema_version != WORKSPACE_COVERAGE_PROCESS_EVIDENCE_HEAD_SCHEMA_VERSION - || head.launch_id != launch_id - || head.generation == 0 - { - bail!("workspace coverage process evidence head is invalid"); - } - match head.state.as_str() { - "launched" - if head.generation == 1 - && head.heartbeat_id.is_none() - && head.termination_id.is_none() => {} - "heartbeat" if head.heartbeat_id.is_some() && head.termination_id.is_none() => {} - "terminated" if head.termination_id.is_some() => {} - _ => bail!("workspace coverage process evidence head state is incoherent"), - } - Ok(()) -} -fn managed_policy_key() -> String { - format!( - "epiphany-local/managed-service-policy/{}", - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID - ) -} -fn envelope_digest(envelope: &cultcache_rs::CultCacheEnvelope) -> String { - let mut digest = Sha256::new(); - digest.update(envelope.r#type.as_bytes()); - digest.update([0]); - digest.update(envelope.key.as_bytes()); - digest.update([0]); - digest.update(&envelope.payload); - format!("sha256-{:x}", digest.finalize()) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION, enroll_host_identity_at, - write_epiphany_cultmesh_workspace_coverage_projector_service_policy, - }; - use cultcache_rs::CacheBackingStore; - use rand_core::{OsRng, RngCore}; - use std::process::Command; - use uuid::Uuid; - - struct FakeObservation { - boot: Option, - process: ProcessInstanceObservation, - } - impl WorkspaceCoverageProcessObservationSource for FakeObservation { - fn boot_identity(&self) -> Option { - self.boot.clone() - } - fn observe(&self, _expected: &ProcessInstanceIdentity) -> ProcessInstanceObservation { - self.process.clone() - } - } - - fn provider_key() -> SigningKey { - let mut seed = [0_u8; 32]; - OsRng.fill_bytes(&mut seed); - SigningKey::from_bytes(&seed) - } - - fn policy() -> Result { - let command = std::env::current_exe()? - .with_file_name(if cfg!(windows) { - "epiphany-workspace-coverage-projector.exe" - } else { - "epiphany-workspace-coverage-projector" - }) - .display() - .to_string(); - Ok(EpiphanyCultMeshManagedServicePolicyEntry { - schema_version: EPIPHANY_CULTMESH_MANAGED_SERVICE_POLICY_SCHEMA_VERSION.to_string(), - policy_id: "managed-service-policy-epiphany-workspace-coverage-projector-service" - .to_string(), - service_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID.to_string(), - command, - args: vec![ - "serve", - "--runtime-store", - "runtime.ccmp", - "--local-verse-store", - "verse.ccmp", - "--runtime-id", - "local", - "--interval-seconds", - "30", - "--heartbeat-interval-seconds", - "10", - "--qdrant-url", - "http://127.0.0.1:6333", - "--ollama-base-url", - "http://127.0.0.1:11434", - "--ollama-model", - "embedding:model", - ] - .into_iter() - .map(str::to_string) - .collect(), - cwd: None, - enabled: true, - cooldown_seconds: 5, - stdout_artifact: "stdout.log".to_string(), - stderr_artifact: "stderr.log".to_string(), - private_state_exposed: false, - }) - } - - fn launch( - policy: &EpiphanyCultMeshManagedServicePolicyEntry, - policy_digest: String, - host: &HostIdentitySigner, - provider: &SigningKey, - ) -> Result { - let now = chrono::Utc::now().to_rfc3339(); - let mut entry = WorkspaceCoverageManagedProcessLaunchEntry { - schema_version: WORKSPACE_COVERAGE_PROCESS_LAUNCH_SCHEMA_VERSION.to_string(), - launch_id: Uuid::new_v4().to_string(), - service_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_SERVICE_ID.to_string(), - provider_daemon_id: EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID.to_string(), - runtime_id: "local".to_string(), - policy_id: policy.policy_id.clone(), - policy_envelope_digest: policy_digest, - command: policy.command.clone(), - args: policy.args.clone(), - cwd: policy.cwd.clone(), - launched_at_utc: now.clone(), - host_identity_id: host.entry().identity_id.clone(), - host_public_key: host.entry().public_key.clone(), - host_assurance: host.entry().assurance.clone(), - host_identity_record_digest: workspace_coverage_host_identity_record_digest( - host.entry(), - )?, - boot_identity: "test-boot-incarnation".to_string(), - process_id: std::process::id(), - process_creation_token: 42, - process_created_at_rfc3339: None, - process_executable_path: std::fs::canonicalize(std::env::current_exe()?)? - .display() - .to_string(), - executable_sha256: format!("sha256-{}", "1".repeat(64)), - provider_incarnation_id: Uuid::new_v4().to_string(), - provider_public_key: provider.verifying_key().to_bytes().to_vec(), - host_signature: Vec::new(), - supervisor_id: "epiphany-daemon-supervisor".to_string(), - identity_captured_at_utc: now, - signature_algorithm: "ed25519".to_string(), - replaces_launch_id: None, - replaces_termination_id: None, - replaces_termination_envelope_digest: None, - }; - sign_workspace_coverage_launch(&mut entry, host)?; - Ok(entry) - } - - fn heartbeat( - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - launch_digest: String, - provider: &SigningKey, - sequence: u64, - ) -> Result { - let mut entry = WorkspaceCoverageProviderHeartbeatEntry { - schema_version: WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_SCHEMA_VERSION.to_string(), - heartbeat_id: Uuid::new_v4().to_string(), - launch_id: launch.launch_id.clone(), - launch_envelope_digest: launch_digest, - service_id: launch.service_id.clone(), - provider_daemon_id: launch.provider_daemon_id.clone(), - runtime_id: launch.runtime_id.clone(), - host_identity_id: launch.host_identity_id.clone(), - host_identity_record_digest: launch.host_identity_record_digest.clone(), - boot_identity: launch.boot_identity.clone(), - process_id: launch.process_id, - process_creation_token: launch.process_creation_token, - process_executable_path: launch.process_executable_path.clone(), - provider_incarnation_id: launch.provider_incarnation_id.clone(), - provider_public_key: launch.provider_public_key.clone(), - sequence, - status: "ready".to_string(), - observed_at_utc: chrono::Utc::now().to_rfc3339(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".to_string(), - }; - sign_workspace_coverage_heartbeat(&mut entry, provider)?; - Ok(entry) - } - - fn persisted_chain( - root: &Path, - ) -> Result<( - std::path::PathBuf, - HostIdentitySigner, - WorkspaceCoverageManagedProcessLaunchEntry, - SigningKey, - )> { - let store = root.join("verse.ccmp"); - let host = enroll_host_identity_at(&root.join("host.ccmp"))?; - let policy = policy()?; - let mut node = open_epiphany_cultmesh_node(&store, "local")?; - node.put(managed_policy_key(), &policy)?; - let policy_envelope = node - .cache() - .get_envelope::(&managed_policy_key())? - .context("test policy envelope absent")?; - let provider = provider_key(); - let launch = launch(&policy, envelope_digest(&policy_envelope), &host, &provider)?; - write_workspace_coverage_managed_process_launch( - &store, - "local", - launch.clone(), - host.entry(), - )?; - let launch_envelope = open_epiphany_cultmesh_node(&store, "local")? - .cache() - .get_envelope::(&launch_key( - &launch.launch_id, - ))? - .context("test launch envelope absent")?; - let pulse = heartbeat(&launch, envelope_digest(&launch_envelope), &provider, 1)?; - write_workspace_coverage_provider_heartbeat(&store, "local", pulse)?; - Ok((store, host, launch, provider)) - } - - fn advancement_sight( - provider: &SigningKey, - sequence: u64, - ) -> Result { - let mut entry = WorkspaceCoverageAdvancementSightEntry { - schema_version: WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_SCHEMA_VERSION.into(), - runtime_id: "local".into(), - workspace_id: "workspace".into(), - launch_id: Uuid::new_v4().to_string(), - launch_envelope_digest: "launch-digest".into(), - provider_incarnation_id: Uuid::new_v4().to_string(), - provider_public_key: provider.verifying_key().to_bytes().to_vec(), - coverage_store_binding_id: "binding".into(), - coverage_store_binding_envelope_digest: "binding-envelope".into(), - coverage_store_file_identity: "file-identity".into(), - runtime_coverage_route_envelope_digest: "route-envelope".into(), - body_binding_sha256: "body-binding".into(), - body_observation_id: "observation".into(), - body_generation: 7, - manifest_root_sha256: "manifest".into(), - claim_id: "claim".into(), - claim_epoch: 3, - plan_id: "plan".into(), - progress_id: Uuid::new_v4().to_string(), - progress_envelope_digest: "progress-envelope".into(), - checkpoint_id: Uuid::new_v4().to_string(), - checkpoint_envelope_digest: "checkpoint-envelope".into(), - sequence, - status: "warming".into(), - completed_units: sequence, - total_units: 10, - last_advanced_at_utc: chrono::Utc::now().to_rfc3339(), - observed_at_utc: chrono::Utc::now().to_rfc3339(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - sign_workspace_coverage_advancement_sight(&mut entry, provider)?; - Ok(entry) - } - - #[test] - fn advancement_sight_signature_refuses_substitution_and_storage_is_latest_only() -> Result<()> { - let provider = provider_key(); - let temp = tempfile::tempdir()?; - let store = temp.path().join("verse.ccmp"); - let first = advancement_sight(&provider, 1)?; - write_workspace_coverage_advancement_sight(&store, "local", first.clone())?; - let mut second = advancement_sight(&provider, 2)?; - second.launch_id = first.launch_id.clone(); - second.provider_incarnation_id = first.provider_incarnation_id.clone(); - second.claim_id = first.claim_id.clone(); - sign_workspace_coverage_advancement_sight(&mut second, &provider)?; - write_workspace_coverage_advancement_sight(&store, "local", second.clone())?; - let sights = SingleFileMessagePackBackingStore::new(&store) - .pull_all()? - .into_iter() - .filter(|entry| entry.r#type == WORKSPACE_COVERAGE_ADVANCEMENT_SIGHT_TYPE) - .collect::>(); - assert_eq!( - sights.len(), - 1, - "advancement sight must replace its exact latest projection" - ); - assert_eq!( - rmp_serde::from_slice::(&sights[0].payload)?, - second - ); - - let mut regression = first.clone(); - regression.launch_id = second.launch_id.clone(); - regression.provider_incarnation_id = second.provider_incarnation_id.clone(); - regression.claim_id = second.claim_id.clone(); - sign_workspace_coverage_advancement_sight(&mut regression, &provider)?; - assert!(write_workspace_coverage_advancement_sight(&store, "local", regression).is_err()); - - let mut substituted = second.clone(); - substituted.checkpoint_envelope_digest = "alien-checkpoint".into(); - let mut unsigned = substituted.clone(); - unsigned.provider_signature.clear(); - assert!( - verify_sight_signature( - COVERAGE_ADVANCEMENT_SIGHT_DOMAIN, - &unsigned, - &substituted.provider_public_key, - &substituted.provider_signature, - ) - .is_err() - ); - Ok(()) - } - - #[test] - fn first_checkpoint_survives_owned_store_reopen_and_resumes_to_terminal_without_body_copies() - -> Result<()> { - let temp = tempfile::tempdir()?; - let verse = temp.path().join("verse.ccmp"); - let host = enroll_host_identity_at(&temp.path().join("host.ccmp"))?; - let policy = policy()?; - let mut node = open_epiphany_cultmesh_node(&verse, "local")?; - node.put(managed_policy_key(), &policy)?; - let policy_envelope = node - .cache() - .get_envelope::(&managed_policy_key())? - .context("test policy envelope absent")?; - let provider = provider_key(); - let launch = launch(&policy, envelope_digest(&policy_envelope), &host, &provider)?; - write_workspace_coverage_managed_process_launch( - &verse, - "local", - launch.clone(), - host.entry(), - )?; - - let repo = tempfile::tempdir()?; - let initialized = std::process::Command::new("git") - .arg("init") - .current_dir(repo.path()) - .output()?; - if !initialized.status.success() { - bail!("resume fixture failed to initialize repository"); - } - std::fs::write(repo.path().join("source.rs"), "fn resumed() {}\n")?; - let runtime = temp.path().join("runtime.cc"); - let body_store = temp.path().join("body.cc"); - let coverage_path = std::fs::canonicalize(temp.path())?.join("coverage.redb"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "local".into(), - display_name: "checkpoint resume".into(), - created_at: "2026-07-17T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "resume-swarm", "2026-07-17T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body_store, &runtime, "resume-workspace")?; - crate::bind_runtime_workspace_coverage_store( - &runtime, - &coverage_path, - "2026-07-17T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let session = crate::RepositoryBodyReadSession::open(&runtime, &basis)?; - let prepared = crate::workspace_coverage_projector::prepare_workspace_coverage_projection( - &session, - "test-provider", - "test-model", - 3, - )?; - let authority = crate::open_workspace_coverage_authority(&runtime)?; - let acquisition = - match crate::workspace_coverage_projector::acquire_workspace_coverage_projection( - &prepared, - &authority.store, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - &launch.provider_incarnation_id, - &launch.launch_id, - )? { - crate::workspace_coverage_projector::WorkspaceCoverageAcquireResult::Acquired( - value, - ) => value, - _ => bail!("resume fixture did not acquire projection"), - }; - let body_before = std::fs::read(&body_store)?; - crate::workspace_coverage_projection_progress::publish_workspace_coverage_progress_genesis( - &body_store, - &authority.store, - &verse, - "local", - host.entry(), - &provider, - 30_000, - )?; - let vector = vec![0.25_f32; 3]; - let mut point_bindings = Vec::new(); - let mut vector_bindings = Vec::new(); - let mut stored = Vec::new(); - for point in &acquisition.plan.planned_points { - let payload = crate::workspace_coverage_projector::payload_for( - &acquisition.obligation, - &acquisition.plan, - point, - ); - point_bindings.push(crate::WorkspaceCoveragePointBinding { - point_id: point.point_id.clone(), - payload_sha256: format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(&payload)?)), - }); - vector_bindings.push(crate::WorkspaceCoverageVectorBinding { - point_id: point.point_id.clone(), - vector_sha256: format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(&vector)?)), - }); - stored.push(crate::semantic_backend::SemanticStoredPoint { - id: point.point_id.clone(), - payload: Some(payload), - vector: Some(vector.clone()), - }); - } - crate::workspace_coverage_projection_batch_checkpoint::admit_observed_workspace_coverage_batch( - &body_store, - &authority.store, - &verse, - "local", - host.entry(), - &provider, - crate::workspace_coverage_projection_batch_checkpoint::ObservedWorkspaceCoverageBatchInput { - claim_id: acquisition.claim.claim_id.clone(), - attempt_id: acquisition.attempt.attempt_id.clone(), - plan_id: acquisition.plan.plan_id.clone(), - first_plan_ordinal: 0, - point_bindings, - vector_bindings, - }, - )?; - let claim_id = acquisition.claim.claim_id.clone(); - let claim_epoch = acquisition.claim.claim_epoch; - drop(acquisition); - drop(authority); - - let reopened = crate::open_workspace_coverage_authority(&runtime)?; - let chain = crate::workspace_coverage_projection_batch_checkpoint::load_authenticated_checkpoint_chain( - &body_store, - &reopened.store, - &verse, - host.entry(), - &claim_id, - claim_epoch, - )?; - assert_eq!(chain.len(), 1); - assert!( - crate::authenticate_current_workspace_coverage_advancement( - &body_store, - &reopened.store, - &verse, - "local", - &launch.launch_id, - host.entry(), - chrono::Utc::now(), - chrono::Duration::minutes(5), - )? - .is_some() - ); - let collection = crate::workspace_coverage_execution_collection( - &prepared.plan.plan_id, - &claim_id, - claim_epoch, - )?; - let obligation = prepared.obligation.clone(); - let plan = prepared.plan.clone(); - let observed = crate::workspace_coverage_projector::observe_final_projection_against_authenticated_checkpoint_chain( - &obligation, - &plan, - &collection, - stored, - &chain, - )?; - let resumed = - match crate::workspace_coverage_projector::acquire_workspace_coverage_projection( - &prepared, - &reopened.store, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - &launch.provider_incarnation_id, - &launch.launch_id, - )? { - crate::workspace_coverage_projector::WorkspaceCoverageAcquireResult::Acquired( - value, - ) => value, - _ => bail!("reopened exact executor did not resume claim"), - }; - crate::workspace_coverage_projector::commit_workspace_coverage_success(&resumed, observed)?; - let terminal_sight = publish_workspace_coverage_terminal_sight( - &verse, - &runtime, - &reopened, - "local", - &launch.launch_id, - host.entry(), - &provider, - chrono::Utc::now(), - )?; - let mut rotated_policy = policy.clone(); - rotated_policy.args[8] = "31".into(); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &verse, - "local", - rotated_policy, - )?; - let historical_sight = publish_workspace_coverage_terminal_sight( - &verse, - &runtime, - &reopened, - "local", - &Uuid::new_v4().to_string(), - host.entry(), - &provider_key(), - chrono::Utc::now(), - )?; - assert_eq!(historical_sight, terminal_sight); - assert_eq!(historical_sight.launch_id, launch.launch_id); - assert_eq!(std::fs::read(&body_store)?, body_before); - assert!(reopened.store.pull_all()?.iter().all(|entry| !matches!( - entry.r#type.as_str(), - crate::BODY_BINDING_TYPE - | crate::BODY_HEAD_TYPE - | crate::BODY_OBSERVATION_TYPE - | crate::BODY_MANIFEST_TYPE - ))); - Ok(()) - } - - #[test] - fn signed_launch_and_per_launch_heartbeat_chain_is_exact() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("verse.ccmp"); - let host_store = temp.path().join("host.ccmp"); - let host = enroll_host_identity_at(&host_store)?; - let policy = policy()?; - let mut node = open_epiphany_cultmesh_node(&store, "local")?; - node.put(managed_policy_key(), &policy)?; - let policy_envelope = node - .cache() - .get_envelope::(&managed_policy_key())? - .context("test policy envelope absent")?; - let provider = provider_key(); - let launch = launch(&policy, envelope_digest(&policy_envelope), &host, &provider)?; - write_workspace_coverage_managed_process_launch( - &store, - "local", - launch.clone(), - host.entry(), - )?; - let launch_envelope = open_epiphany_cultmesh_node(&store, "local")? - .cache() - .get_envelope::(&launch_key( - &launch.launch_id, - ))? - .context("test launch envelope absent")?; - let first = heartbeat(&launch, envelope_digest(&launch_envelope), &provider, 1)?; - write_workspace_coverage_provider_heartbeat(&store, "local", first.clone())?; - assert_eq!( - load_latest_workspace_coverage_provider_heartbeat(&store, "local", &launch.launch_id)?, - Some(first.clone()) - ); - let mut second = heartbeat(&launch, envelope_digest(&launch_envelope), &provider, 2)?; - second.observed_at_utc = (DateTime::parse_from_rfc3339(&first.observed_at_utc)? - + chrono::Duration::seconds(1)) - .to_rfc3339(); - sign_workspace_coverage_heartbeat(&mut second, &provider)?; - write_workspace_coverage_provider_heartbeat(&store, "local", second.clone())?; - assert_eq!( - load_workspace_coverage_provider_heartbeat(&store, "local", &second.heartbeat_id)?, - Some(second) - ); - assert_eq!( - load_workspace_coverage_provider_heartbeat(&store, "local", &first.heartbeat_id)?, - Some(first.clone()) - ); - assert_eq!( - SingleFileMessagePackBackingStore::new(&store) - .pull_all()? - .into_iter() - .filter(|entry| entry.r#type == WORKSPACE_COVERAGE_PROVIDER_HEARTBEAT_TYPE) - .count(), - 3, - "latest is a derived head over immutable heartbeat evidence" - ); - - let mut forged = first.clone(); - forged.heartbeat_id = Uuid::new_v4().to_string(); - forged.status = "degraded".to_string(); - assert!(write_workspace_coverage_provider_heartbeat(&store, "local", forged).is_err()); - - let gap = heartbeat(&launch, envelope_digest(&launch_envelope), &provider, 4)?; - assert!(write_workspace_coverage_provider_heartbeat(&store, "local", gap).is_err()); - - let mut collision = launch.clone(); - collision.executable_sha256 = format!("sha256-{}", "2".repeat(64)); - sign_workspace_coverage_launch(&mut collision, &host)?; - assert!( - write_workspace_coverage_managed_process_launch( - &store, - "local", - collision, - host.entry() - ) - .is_err() - ); - Ok(()) - } - - #[test] - fn reserved_documents_refuse_wrong_runtime_tuple_and_status() -> Result<()> { - let temp = tempfile::tempdir()?; - let host = enroll_host_identity_at(&temp.path().join("host.ccmp"))?; - let policy = policy()?; - let provider = provider_key(); - let mut launch = launch( - &policy, - format!("sha256-{}", "3".repeat(64)), - &host, - &provider, - )?; - assert!(validate_launch(&launch, host.entry()).is_ok()); - launch.supervisor_id = "some-other-writer".to_string(); - sign_workspace_coverage_launch(&mut launch, &host)?; - assert!(validate_launch(&launch, host.entry()).is_err()); - - let mut heartbeat = heartbeat(&launch, format!("sha256-{}", "4".repeat(64)), &provider, 1)?; - heartbeat.status = "healthy-ish".to_string(); - sign_workspace_coverage_heartbeat(&mut heartbeat, &provider)?; - assert!(validate_heartbeat_shape(&heartbeat).is_err()); - Ok(()) - } - - #[test] - fn termination_observation_accepts_only_exact_native_proofs_and_is_immutable() -> Result<()> { - let cases = vec![ - ( - "exact_exited", - ProcessInstanceObservation::ExactExited { exit_code: Some(7) }, - ), - ("process_missing", ProcessInstanceObservation::Missing), - ( - "process_replaced", - ProcessInstanceObservation::Replaced { - observed: ProcessInstanceIdentity { - process_id: 777, - creation_token: 888, - created_at_rfc3339: None, - executable_path: std::fs::canonicalize(std::env::current_exe()?)?, - }, - }, - ), - ]; - for (expected_outcome, process) in cases { - let temp = tempfile::tempdir()?; - let (store, host, launch, _provider) = persisted_chain(temp.path())?; - let source = FakeObservation { - boot: Some(launch.boot_identity.clone()), - process, - }; - let proof = write_workspace_coverage_process_termination_observation_with_source( - &store, - "local", - &launch.launch_id, - &host, - &source, - )?; - assert_eq!(proof.outcome, expected_outcome); - assert_eq!( - authenticate_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - host.entry(), - )?, - proof - ); - assert!( - write_workspace_coverage_process_termination_observation_with_source( - &store, - "local", - &launch.launch_id, - &host, - &source, - ) - .expect_err("termination key is immutable") - .to_string() - .contains("already has terminal evidence") - ); - let mut advanced_policy = policy()?; - advanced_policy.args[8] = "31".into(); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, - "local", - advanced_policy, - )?; - assert_eq!( - authenticate_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - host.entry(), - )?, - proof, - "policy rotation must not erase historical process evidence" - ); - } - - let temp = tempfile::tempdir()?; - let (store, host, launch, _provider) = persisted_chain(temp.path())?; - let source = FakeObservation { - boot: Some("proved-new-boot".to_string()), - process: ProcessInstanceObservation::ExactAlive, - }; - let proof = write_workspace_coverage_process_termination_observation_with_source( - &store, - "local", - &launch.launch_id, - &host, - &source, - )?; - assert_eq!(proof.outcome, "boot_superseded"); - assert_ne!(proof.expected_boot_identity, proof.observed_boot_identity); - Ok(()) - } - - #[test] - fn termination_observation_refuses_missing_boot_alive_and_uncertain_processes() -> Result<()> { - let cases = vec![ - FakeObservation { - boot: None, - process: ProcessInstanceObservation::Missing, - }, - FakeObservation { - boot: Some("test-boot-incarnation".into()), - process: ProcessInstanceObservation::ExactAlive, - }, - FakeObservation { - boot: Some("test-boot-incarnation".into()), - process: ProcessInstanceObservation::Inaccessible, - }, - FakeObservation { - boot: Some("test-boot-incarnation".into()), - process: ProcessInstanceObservation::Indeterminate { - reason: "host lied".into(), - }, - }, - ]; - for source in cases { - let temp = tempfile::tempdir()?; - let (store, host, launch, _provider) = persisted_chain(temp.path())?; - assert!( - write_workspace_coverage_process_termination_observation_with_source( - &store, - "local", - &launch.launch_id, - &host, - &source, - ) - .is_err() - ); - assert!( - load_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - )? - .is_none() - ); - } - Ok(()) - } - - #[test] - fn typed_process_observation_never_writes_termination_state() -> Result<()> { - let cases = vec![ - ( - ProcessInstanceObservation::ExactAlive, - WorkspaceCoverageProcessLifecycleObservation::ExactAlive, - ), - ( - ProcessInstanceObservation::Missing, - WorkspaceCoverageProcessLifecycleObservation::Missing, - ), - ( - ProcessInstanceObservation::Inaccessible, - WorkspaceCoverageProcessLifecycleObservation::Inaccessible, - ), - ( - ProcessInstanceObservation::Indeterminate { - reason: "ambiguous kernel sight".into(), - }, - WorkspaceCoverageProcessLifecycleObservation::Indeterminate { - reason: "ambiguous kernel sight".into(), - }, - ), - ]; - for (process, expected) in cases { - let temp = tempfile::tempdir()?; - let (store, _host, launch, _provider) = persisted_chain(temp.path())?; - let observed = observe_workspace_coverage_process_with_source( - &launch, - &FakeObservation { - boot: Some(launch.boot_identity.clone()), - process, - }, - ); - assert_eq!(observed, expected); - assert!( - load_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - )? - .is_none() - ); - } - Ok(()) - } - - #[test] - fn public_process_observation_refuses_stale_launch_policy_substitution() -> Result<()> { - let temp = tempfile::tempdir()?; - let (store, host, launch, _provider) = persisted_chain(temp.path())?; - let mut moved_policy = policy()?; - moved_policy.args[8] = "31".into(); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, - "local", - moved_policy, - )?; - assert!( - observe_workspace_coverage_managed_process( - &store, - "local", - &launch.launch_id, - host.entry(), - ) - .expect_err("stale launch must not be observed as current authority") - .to_string() - .contains("disagrees with current managed policy") - ); - assert!( - load_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - )? - .is_none() - ); - Ok(()) - } - - #[test] - fn policy_rotation_preserves_historical_termination_authority() -> Result<()> { - let temp = tempfile::tempdir()?; - let (store, host, launch, _provider) = persisted_chain(temp.path())?; - let mut moved_policy = policy()?; - moved_policy.args[8] = "31".into(); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &store, - "local", - moved_policy, - )?; - - let termination = write_workspace_coverage_process_termination_observation_with_source( - &store, - "local", - &launch.launch_id, - &host, - &FakeObservation { - boot: Some(launch.boot_identity.clone()), - process: ProcessInstanceObservation::Missing, - }, - )?; - assert_eq!(termination.policy_id, launch.policy_id); - assert_eq!( - termination.policy_envelope_digest, - launch.policy_envelope_digest - ); - authenticate_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - host.entry(), - )?; - Ok(()) - } - - #[test] - fn termination_before_first_heartbeat_seals_the_process_evidence_head() -> Result<()> { - let temp = tempfile::tempdir()?; - let store = temp.path().join("verse.ccmp"); - let host = enroll_host_identity_at(&temp.path().join("host.ccmp"))?; - let policy = policy()?; - let mut node = open_epiphany_cultmesh_node(&store, "local")?; - node.put(managed_policy_key(), &policy)?; - let policy_envelope = node - .cache() - .get_envelope::(&managed_policy_key())? - .context("test policy envelope absent")?; - let provider = provider_key(); - let launch = launch(&policy, envelope_digest(&policy_envelope), &host, &provider)?; - write_workspace_coverage_managed_process_launch( - &store, - "local", - launch.clone(), - host.entry(), - )?; - let source = FakeObservation { - boot: Some(launch.boot_identity.clone()), - process: ProcessInstanceObservation::Missing, - }; - let termination = write_workspace_coverage_process_termination_observation_with_source( - &store, - "local", - &launch.launch_id, - &host, - &source, - )?; - assert!(termination.heartbeat_id.is_none()); - assert!(termination.heartbeat_envelope_digest.is_none()); - authenticate_workspace_coverage_process_termination_observation( - &store, - "local", - &launch.launch_id, - host.entry(), - )?; - - let launch_envelope = open_epiphany_cultmesh_node(&store, "local")? - .cache() - .get_envelope::(&launch_key( - &launch.launch_id, - ))? - .context("test launch envelope absent")?; - let pulse = heartbeat(&launch, envelope_digest(&launch_envelope), &provider, 1)?; - assert!( - write_workspace_coverage_provider_heartbeat(&store, "local", pulse).is_err(), - "a late heartbeat must not resurrect a terminated launch" - ); - Ok(()) - } - - #[test] - fn body_recovery_is_one_exact_evidence_fenced_transaction() -> Result<()> { - let temp = tempfile::tempdir()?; - let (verse, host, old_launch, old_provider) = persisted_chain(temp.path())?; - - let repo = temp.path().join("repo"); - std::fs::create_dir_all(&repo)?; - Command::new("git") - .args(["init"]) - .current_dir(&repo) - .output()?; - std::fs::write(repo.join("source.rs"), "fn awake() {}\n")?; - Command::new("git") - .args(["add", "."]) - .current_dir(&repo) - .output()?; - let runtime = temp.path().join("runtime.cc"); - let body_store = temp.path().join("body.ccmp"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "local".into(), - display_name: "recovery-test".into(), - created_at: "2026-07-16T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "recovery-swarm", "2026-07-16T00:00:01Z")?; - crate::bind_repository_body(&repo, &body_store, &runtime, "recovery-workspace")?; - let coverage_store_path = std::fs::canonicalize(temp.path())?.join("coverage.redb"); - crate::bind_runtime_workspace_coverage_store( - &runtime, - &coverage_store_path, - "2026-07-16T00:00:02Z", - )?; - let coverage = crate::open_workspace_coverage_authority(&runtime)?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let session = crate::RepositoryBodyReadSession::open(&runtime, &basis)?; - let prepared = crate::workspace_coverage_projector::prepare_workspace_coverage_projection( - &session, - "test-provider", - "test-model", - 3, - )?; - let acquired = - match crate::workspace_coverage_projector::acquire_workspace_coverage_projection( - &prepared, - &coverage.store, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - &old_launch.provider_incarnation_id, - &old_launch.launch_id, - )? { - crate::workspace_coverage_projector::WorkspaceCoverageAcquireResult::Acquired( - value, - ) => value, - _ => bail!("fixture did not acquire old claim"), - }; - publish_workspace_coverage_claim_sight( - &verse, - &runtime, - &coverage, - &acquired, - "local", - &old_launch.launch_id, - host.entry(), - &old_provider, - chrono::Utc::now(), - )?; - assert!( - authenticate_current_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .is_some() - ); - - let mut rotated_policy = policy()?; - rotated_policy.args[8] = "31".into(); - write_epiphany_cultmesh_workspace_coverage_projector_service_policy( - &verse, - "local", - rotated_policy, - )?; - assert!( - authenticate_current_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - ) - .expect_err("ordinary provider work must reject a stale-policy claim") - .to_string() - .contains("current managed policy") - ); - assert!( - authenticate_recovery_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .is_some(), - "recovery must preserve the old signed claim/body lineage" - ); - - let source = FakeObservation { - boot: Some(old_launch.boot_identity.clone()), - process: ProcessInstanceObservation::Missing, - }; - let termination = write_workspace_coverage_process_termination_observation_with_source( - &verse, - "local", - &old_launch.launch_id, - &host, - &source, - )?; - let (_, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - &verse, - "local", - &old_launch.launch_id, - host.entry(), - )?; - let old_claim_id = acquired.claim.claim_id.clone(); - let old_claim_epoch = acquired.claim.claim_epoch; - drop(acquired); - drop(coverage); - - let node = open_epiphany_cultmesh_node(&verse, "local")?; - let policy_envelope = node - .cache() - .get_envelope::(&managed_policy_key())? - .context("policy missing")?; - let policy: EpiphanyCultMeshManagedServicePolicyEntry = - rmp_serde::from_slice(&policy_envelope.payload)?; - let body_before_refusal = std::fs::read(&body_store)?; - let out_of_order_provider = provider_key(); - let mut out_of_order = launch( - &policy, - envelope_digest(&policy_envelope), - &host, - &out_of_order_provider, - )?; - out_of_order.launched_at_utc = termination.observed_at_utc.clone(); - out_of_order.identity_captured_at_utc = termination.observed_at_utc.clone(); - sign_workspace_coverage_launch(&mut out_of_order, &host)?; - write_workspace_coverage_managed_process_launch( - &verse, - "local", - out_of_order.clone(), - host.entry(), - )?; - let out_of_order_envelope = open_epiphany_cultmesh_node(&verse, "local")? - .cache() - .get_envelope::(&launch_key( - &out_of_order.launch_id, - ))? - .context("out-of-order launch missing")?; - let out_of_order_ready = heartbeat( - &out_of_order, - envelope_digest(&out_of_order_envelope), - &out_of_order_provider, - 1, - )?; - write_workspace_coverage_provider_heartbeat(&verse, "local", out_of_order_ready.clone())?; - assert!( - crate::workspace_coverage_projector::recover_workspace_coverage_projection_with_authority( - &crate::open_workspace_coverage_authority(&runtime)?, - &runtime, - &verse, - "local", - host.entry(), - &old_launch.launch_id, - &out_of_order.launch_id, - &out_of_order_ready.heartbeat_id, - &old_claim_id, - ) - .is_err(), - "unbound replacement must be refused" - ); - assert_eq!(std::fs::read(&body_store)?, body_before_refusal); - - let intermediate_provider = provider_key(); - let mut intermediate = launch( - &policy, - envelope_digest(&policy_envelope), - &host, - &intermediate_provider, - )?; - intermediate.replaces_launch_id = Some(old_launch.launch_id.clone()); - intermediate.replaces_termination_id = Some(termination.termination_id.clone()); - intermediate.replaces_termination_envelope_digest = Some(termination_digest); - sign_workspace_coverage_launch(&mut intermediate, &host)?; - write_workspace_coverage_managed_process_launch( - &verse, - "local", - intermediate.clone(), - host.entry(), - )?; - let intermediate_source = FakeObservation { - boot: Some(intermediate.boot_identity.clone()), - process: ProcessInstanceObservation::Missing, - }; - let intermediate_termination = - write_workspace_coverage_process_termination_observation_with_source( - &verse, - "local", - &intermediate.launch_id, - &host, - &intermediate_source, - )?; - let (_, intermediate_termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - &verse, - "local", - &intermediate.launch_id, - host.entry(), - )?; - let replacement_provider = provider_key(); - let mut replacement = launch( - &policy, - envelope_digest(&policy_envelope), - &host, - &replacement_provider, - )?; - replacement.replaces_launch_id = Some(intermediate.launch_id.clone()); - replacement.replaces_termination_id = Some(intermediate_termination.termination_id.clone()); - replacement.replaces_termination_envelope_digest = Some(intermediate_termination_digest); - sign_workspace_coverage_launch(&mut replacement, &host)?; - write_workspace_coverage_managed_process_launch( - &verse, - "local", - replacement.clone(), - host.entry(), - )?; - let competing_provider = provider_key(); - let mut competing = launch( - &policy, - envelope_digest(&policy_envelope), - &host, - &competing_provider, - )?; - competing.replaces_launch_id = Some(intermediate.launch_id.clone()); - competing.replaces_termination_id = Some(intermediate_termination.termination_id.clone()); - competing.replaces_termination_envelope_digest = - replacement.replaces_termination_envelope_digest.clone(); - sign_workspace_coverage_launch(&mut competing, &host)?; - assert!( - write_workspace_coverage_managed_process_launch( - &verse, - "local", - competing, - host.entry(), - ) - .is_err(), - "one termination must authorize at most one replacement launch" - ); - let replacement_envelope = open_epiphany_cultmesh_node(&verse, "local")? - .cache() - .get_envelope::(&launch_key( - &replacement.launch_id, - ))? - .context("replacement launch missing")?; - let initial_ready = heartbeat( - &replacement, - envelope_digest(&replacement_envelope), - &replacement_provider, - 1, - )?; - write_workspace_coverage_provider_heartbeat(&verse, "local", initial_ready)?; - - let body_before_refusal = std::fs::read(&body_store)?; - let mut degraded = heartbeat( - &replacement, - envelope_digest(&replacement_envelope), - &replacement_provider, - 2, - )?; - degraded.status = "degraded".into(); - sign_workspace_coverage_heartbeat(&mut degraded, &replacement_provider)?; - write_workspace_coverage_provider_heartbeat(&verse, "local", degraded.clone())?; - assert!( - crate::workspace_coverage_projector::recover_workspace_coverage_projection_with_authority( - &crate::open_workspace_coverage_authority(&runtime)?, - &runtime, - &verse, - "local", - host.entry(), - &old_launch.launch_id, - &replacement.launch_id, - °raded.heartbeat_id, - &old_claim_id, - ) - .is_err(), - "degraded replacement must not inherit Body authority" - ); - assert_eq!(std::fs::read(&body_store)?, body_before_refusal); - - let ready = heartbeat( - &replacement, - envelope_digest(&replacement_envelope), - &replacement_provider, - 3, - )?; - write_workspace_coverage_provider_heartbeat(&verse, "local", ready.clone())?; - let later_ready = heartbeat( - &replacement, - envelope_digest(&replacement_envelope), - &replacement_provider, - 4, - )?; - write_workspace_coverage_provider_heartbeat(&verse, "local", later_ready)?; - let directive = write_workspace_coverage_recovery_directive( - &verse, - &runtime, - "local", - &authenticate_recovery_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .context("current claim sight missing before recovery directive")?, - &replacement.launch_id, - &ready.heartbeat_id, - &host, - )?; - assert!( - authenticate_workspace_coverage_recovery_directive( - &verse, - &runtime, - "local", - &replacement.launch_id, - host.entry(), - )? - .is_some() - ); - let mut conflicting_lineage = authenticate_recovery_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .context("claim sight missing for conflict check")?; - conflicting_lineage.claim_id = uuid::Uuid::new_v4().to_string(); - assert!( - write_workspace_coverage_recovery_directive( - &verse, - &runtime, - "local", - &conflicting_lineage, - &replacement.launch_id, - &ready.heartbeat_id, - &host, - ) - .is_err(), - "a replacement directive must refuse conflicting claim lineage" - ); - - let recovered = crate::workspace_coverage_projector::recover_workspace_coverage_projection_with_authority( - &crate::open_workspace_coverage_authority(&runtime)?, - &runtime, - &verse, - "local", - host.entry(), - &old_launch.launch_id, - &replacement.launch_id, - &ready.heartbeat_id, - &old_claim_id, - )?; - assert_eq!(recovered.claim_epoch, old_claim_epoch + 1); - assert_eq!(recovered.managed_process_launch_id, replacement.launch_id); - assert_eq!( - recovered.executor_incarnation, - replacement.provider_incarnation_id - ); - let reissued = write_workspace_coverage_recovery_directive( - &verse, - &runtime, - "local", - &authenticate_recovery_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .context("old claim sight must survive the CAS-to-sight crash boundary")?, - &replacement.launch_id, - &ready.heartbeat_id, - &host, - )?; - assert_eq!( - reissued, directive, - "directive reissue must be byte-identical" - ); - let coverage = crate::open_workspace_coverage_authority(&runtime)?; - let resumed = - match crate::workspace_coverage_projector::acquire_workspace_coverage_projection( - &prepared, - &coverage.store, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - &replacement.provider_incarnation_id, - &replacement.launch_id, - )? { - crate::workspace_coverage_projector::WorkspaceCoverageAcquireResult::Acquired( - resumed, - ) => resumed, - _ => bail!("exact replacement incarnation did not resume its recovered claim"), - }; - assert_eq!(resumed.claim.claim_id, recovered.claim_id); - publish_workspace_coverage_claim_sight( - &verse, - &runtime, - &coverage, - &resumed, - "local", - &replacement.launch_id, - host.entry(), - &replacement_provider, - chrono::Utc::now(), - )?; - assert_eq!( - authenticate_current_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .context("successor sight missing after recovery resume")? - .claim_id, - recovered.claim_id, - ); - drop(resumed); - assert!(matches!( - crate::workspace_coverage_projector::acquire_workspace_coverage_projection( - &prepared, - &coverage.store, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - "wrong-incarnation", - &replacement.launch_id, - )?, - crate::workspace_coverage_projector::WorkspaceCoverageAcquireResult::Contended - )); - let opening = coverage.store.pull_all()?; - let old_history: crate::workspace_coverage_projector::WorkspaceCoverageProjectionClaim = - rmp_serde::from_slice( - &opening - .iter() - .find(|entry| { - entry.r#type == "gamecult.epiphany.workspace_coverage_projection_claim" - && entry.key == format!("history/{old_claim_id}") - }) - .context("failed claim history missing")? - .payload, - )?; - assert_eq!(old_history.status, "failed"); - assert!(old_history.termination_evidence_digest.is_some()); - drop(coverage); - let recovery_id = recovered.recovery_receipt_id.as_str(); - let recovery_digest = recovered.recovery_receipt_digest.as_str(); - crate::workspace_coverage_projector::authenticate_workspace_coverage_recovery_receipt( - &runtime, - &verse, - "local", - host.entry(), - recovery_id, - recovery_digest, - )?; - assert_eq!( - old_history.recovery_receipt_id.as_deref(), - Some(recovery_id) - ); - assert_eq!( - old_history.recovery_receipt_digest.as_deref(), - Some(recovery_digest) - ); - let replayed = - crate::workspace_coverage_projector::recover_workspace_coverage_projection_with_authority( - &crate::open_workspace_coverage_authority(&runtime)?, - &runtime, - &verse, - "local", - host.entry(), - &old_launch.launch_id, - &replacement.launch_id, - &ready.heartbeat_id, - &old_claim_id, - )?; - assert_eq!( - replayed, recovered, - "exact crash-boundary replay must be idempotent" - ); - std::fs::write(repo.join("after-recovery.rs"), "fn newer_body() {}\n")?; - Command::new("git") - .args(["add", "."]) - .current_dir(&repo) - .output()?; - let newer_basis = crate::observe_runtime_repository_body_basis(&runtime)?; - assert!(newer_basis.generation > basis.generation); - assert!( - authenticate_current_workspace_coverage_claim_sight( - &verse, - &runtime, - "local", - host.entry(), - )? - .is_none(), - "a prior-Body claim sight must not become the current recovery target" - ); - assert!( - authenticate_workspace_coverage_recovery_directive( - &verse, - &runtime, - "local", - &directive.replacement_launch_id, - host.entry(), - )? - .is_none(), - "a prior-Body directive must become inert after Body advances" - ); - Ok(()) - } -} diff --git a/epiphany-core/src/workspace_coverage_projection_batch_checkpoint.rs b/epiphany-core/src/workspace_coverage_projection_batch_checkpoint.rs deleted file mode 100644 index 3dae40cf..00000000 --- a/epiphany-core/src/workspace_coverage_projection_batch_checkpoint.rs +++ /dev/null @@ -1,1674 +0,0 @@ -use crate::workspace_coverage_process_documents::authenticate_workspace_coverage_managed_process_launch_with_envelope_digest; -use crate::workspace_coverage_projector::{ - ATTEMPT_TYPE, CLAIM_TYPE, OBLIGATION_TYPE, PLAN_TYPE, WorkspaceCoverageProjectionAttempt, - WorkspaceCoverageProjectionClaim, exact_obligation_body_authority, payload_for, - validate_claim_attempt_link, validate_projection_attempt, validate_projection_claim, - workspace_coverage_claim_key, -}; -use crate::workspace_retrieval_coverage::{ - WorkspaceCoverageObligation, WorkspaceCoverageProjectionPlan, - workspace_coverage_execution_collection, -}; -use crate::{ - BODY_BINDING_KEY, BODY_BINDING_TYPE, BODY_HEAD_KEY, BODY_HEAD_TYPE, BODY_MANIFEST_TYPE, - BODY_OBSERVATION_TYPE, HostIncarnationIdentityEntry, RepositoryBodyBinding, RepositoryBodyHead, - RepositoryBodyManifest, RepositoryBodyObservation, WorkspaceCoverageManagedProcessLaunchEntry, - WorkspaceCoveragePointBinding, WorkspaceCoverageVectorBinding, - validate_workspace_coverage_projection_plan, -}; -use anyhow::{Context, Result, anyhow, bail}; -use chrono::DateTime; -use cultcache_rs::{ - CacheBackingStore, CultCacheEnvelope, DatabaseEntry, OwnedRedbMessagePackBackingStore, - SingleFileMessagePackBackingStore, -}; -use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; -use serde::Serialize; -use sha2::{Digest, Sha256}; -use std::path::Path; - -pub const WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE: &str = - "gamecult.epiphany.workspace_coverage_projection_batch_checkpoint"; -pub const WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_projection_batch_checkpoint.v0"; -pub const WORKSPACE_COVERAGE_BATCH_CHECKPOINT_MAX_POINTS: usize = 128; -pub(crate) const WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_HEAD_TYPE: &str = - "gamecult.epiphany.workspace_coverage_projection_batch_checkpoint_head"; -const HEAD_TYPE: &str = WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_HEAD_TYPE; -const HEAD_SCHEMA: &str = - "gamecult.epiphany.workspace_coverage_projection_batch_checkpoint_head.v0"; -const OBSERVATION_METHOD: &str = "provider-attested-qdrant-readback-v0"; -const SIGNATURE_DOMAIN: &[u8] = b"epiphany.workspace-coverage.batch-checkpoint.v0\0"; - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_projection_batch_checkpoint", - schema = "WorkspaceCoverageProjectionBatchCheckpointEntry" -)] -pub struct WorkspaceCoverageProjectionBatchCheckpointEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub checkpoint_id: String, - #[cultcache(key = 2)] - pub sequence: u64, - #[cultcache(key = 3, default)] - pub predecessor_checkpoint_id: Option, - #[cultcache(key = 4, default)] - pub predecessor_checkpoint_envelope_digest: Option, - #[cultcache(key = 5)] - pub runtime_id: String, - #[cultcache(key = 6)] - pub workspace_id: String, - #[cultcache(key = 7)] - pub body_binding_sha256: String, - #[cultcache(key = 8)] - pub body_binding_envelope_digest: String, - #[cultcache(key = 9)] - pub body_head_envelope_digest: String, - #[cultcache(key = 10)] - pub body_observation_id: String, - #[cultcache(key = 11)] - pub body_generation: u64, - #[cultcache(key = 12)] - pub body_observation_envelope_digest: String, - #[cultcache(key = 13)] - pub manifest_root_sha256: String, - #[cultcache(key = 14)] - pub body_manifest_envelope_digest: String, - #[cultcache(key = 15)] - pub obligation_id: String, - #[cultcache(key = 16)] - pub obligation_envelope_digest: String, - #[cultcache(key = 17)] - pub plan_id: String, - #[cultcache(key = 18)] - pub plan_envelope_digest: String, - #[cultcache(key = 19)] - pub claim_id: String, - #[cultcache(key = 20)] - pub claim_epoch: u64, - #[cultcache(key = 21)] - pub claim_envelope_digest: String, - #[cultcache(key = 22)] - pub attempt_id: String, - #[cultcache(key = 23)] - pub attempt_envelope_digest: String, - #[cultcache(key = 24)] - pub managed_process_launch_id: String, - #[cultcache(key = 25)] - pub managed_process_launch_envelope_digest: String, - #[cultcache(key = 26)] - pub provider_incarnation_id: String, - #[cultcache(key = 27)] - pub provider_public_key: Vec, - #[cultcache(key = 28)] - pub projection_schema_version: String, - #[cultcache(key = 29)] - pub chunker_id: String, - #[cultcache(key = 30)] - pub embedding_provider_id: String, - #[cultcache(key = 31)] - pub embedding_artifact_identity: String, - #[cultcache(key = 32)] - pub vector_dimensions: u32, - #[cultcache(key = 33)] - pub collection_name: String, - #[cultcache(key = 34)] - pub batch_ordinal: u64, - #[cultcache(key = 35)] - pub first_plan_ordinal: u64, - #[cultcache(key = 36)] - pub point_count: u64, - #[cultcache(key = 37)] - pub cumulative_point_count: u64, - #[cultcache(key = 38)] - pub total_point_count: u64, - #[cultcache(key = 39)] - pub point_ids: Vec, - #[cultcache(key = 40)] - pub point_bindings: Vec, - #[cultcache(key = 41)] - pub vector_bindings: Vec, - #[cultcache(key = 42)] - pub observed_at_utc: String, - #[cultcache(key = 43)] - pub observation_method: String, - #[cultcache(key = 44)] - pub provider_signature: Vec, - #[cultcache(key = 45)] - pub signature_algorithm: String, -} - -/// Derived claim-local lookup cache. It grants no checkpoint or Qdrant -/// authority; consumers authenticate the immutable event named here. -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_projection_batch_checkpoint_head", - schema = "WorkspaceCoverageProjectionBatchCheckpointHeadEntry" -)] -pub struct WorkspaceCoverageProjectionBatchCheckpointHeadEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub claim_id: String, - #[cultcache(key = 2)] - pub claim_epoch: u64, - #[cultcache(key = 3)] - pub checkpoint_id: String, - #[cultcache(key = 4)] - pub checkpoint_envelope_digest: String, - #[cultcache(key = 5)] - pub sequence: u64, - #[cultcache(key = 6)] - pub cumulative_point_count: u64, - #[cultcache(key = 7)] - pub total_point_count: u64, - #[cultcache(key = 8)] - pub collection_name: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageProjectionBatchCheckpointAdmission { - /// Provider-attested Body admission. Live Qdrant readback remains a later - /// port integration and is not proven by this result. - pub checkpoint: WorkspaceCoverageProjectionBatchCheckpointEntry, - pub checkpoint_envelope_digest: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct ObservedWorkspaceCoverageBatchInput { - pub claim_id: String, - pub attempt_id: String, - pub plan_id: String, - pub first_plan_ordinal: u64, - pub point_bindings: Vec, - pub vector_bindings: Vec, -} - -pub(crate) fn admit_observed_workspace_coverage_batch( - body_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - runtime_id: &str, - trusted_host: &HostIncarnationIdentityEntry, - provider_signing_key: &SigningKey, - observed: ObservedWorkspaceCoverageBatchInput, -) -> Result { - validate_observed_batch_input(&observed)?; - let opening = coverage_store.pull_all()?; - let body_opening = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - let claim_env = find_current_claim(&opening, &body_opening)?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &claim.attempt_id)?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_claim_attempt_link(&claim, &attempt)?; - if claim.status != "running" - || claim.claim_id != observed.claim_id - || attempt.attempt_id != observed.attempt_id - || claim.plan_id != observed.plan_id - { - bail!("observed batch expected identity disagrees with current running authority"); - } - let obligation_env = find(&opening, OBLIGATION_TYPE, &claim.obligation_id)?; - let plan_env = find(&opening, PLAN_TYPE, &claim.plan_id)?; - let obligation: WorkspaceCoverageObligation = decode(obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(plan_env)?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - let authority = exact_obligation_body_authority(&body_opening, &obligation)?; - let binding_env = find(&authority, BODY_BINDING_TYPE, BODY_BINDING_KEY)?; - let body_head_env = find(&authority, BODY_HEAD_TYPE, BODY_HEAD_KEY)?; - let observation_env = find( - &authority, - BODY_OBSERVATION_TYPE, - &obligation.body_observation_id, - )?; - let manifest_env = find( - &authority, - BODY_MANIFEST_TYPE, - &obligation.manifest_root_sha256, - )?; - let binding: RepositoryBodyBinding = decode(binding_env)?; - if binding.runtime_id != runtime_id || obligation.runtime_id != runtime_id { - bail!("observed batch runtime disagrees with Body authority"); - } - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id, - &claim.managed_process_launch_id, - trusted_host, - )?; - if launch.provider_incarnation_id != claim.executor_incarnation - || launch.provider_daemon_id != claim.executor_id - || provider_signing_key.verifying_key().to_bytes().as_slice() - != launch.provider_public_key.as_slice() - { - bail!("observed batch signer/launch disagrees with claim executor"); - } - let head_key = checkpoint_head_key(&claim.claim_id, claim.claim_epoch); - let prior: Option = opening - .iter() - .find(|env| env.r#type == HEAD_TYPE && env.key == head_key) - .map(decode) - .transpose()?; - let sequence = prior.as_ref().map_or(Ok(1), |head| { - head.sequence - .checked_add(1) - .ok_or_else(|| anyhow!("checkpoint sequence exhausted")) - })?; - let batch_ordinal = sequence - .checked_sub(1) - .ok_or_else(|| anyhow!("checkpoint ordinal underflow"))?; - let point_count: u64 = observed.point_bindings.len().try_into()?; - let cumulative = observed - .first_plan_ordinal - .checked_add(point_count) - .ok_or_else(|| anyhow!("checkpoint cumulative count overflow"))?; - let point_ids = observed - .point_bindings - .iter() - .map(|binding| binding.point_id.clone()) - .collect(); - let mut entry = WorkspaceCoverageProjectionBatchCheckpointEntry { - schema_version: WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_SCHEMA_VERSION.into(), - checkpoint_id: uuid::Uuid::new_v4().to_string(), - sequence, - predecessor_checkpoint_id: prior.as_ref().map(|head| head.checkpoint_id.clone()), - predecessor_checkpoint_envelope_digest: prior - .as_ref() - .map(|head| head.checkpoint_envelope_digest.clone()), - runtime_id: runtime_id.into(), - workspace_id: obligation.workspace_id.clone(), - body_binding_sha256: obligation.body_binding_sha256.clone(), - body_binding_envelope_digest: envelope_digest(binding_env), - body_head_envelope_digest: envelope_digest(body_head_env), - body_observation_id: obligation.body_observation_id.clone(), - body_generation: obligation.body_generation, - body_observation_envelope_digest: envelope_digest(observation_env), - manifest_root_sha256: obligation.manifest_root_sha256.clone(), - body_manifest_envelope_digest: envelope_digest(manifest_env), - obligation_id: obligation.obligation_id.clone(), - obligation_envelope_digest: envelope_digest(obligation_env), - plan_id: plan.plan_id.clone(), - plan_envelope_digest: envelope_digest(plan_env), - claim_id: claim.claim_id.clone(), - claim_epoch: claim.claim_epoch, - claim_envelope_digest: envelope_digest(claim_env), - attempt_id: attempt.attempt_id.clone(), - attempt_envelope_digest: envelope_digest(attempt_env), - managed_process_launch_id: launch.launch_id.clone(), - managed_process_launch_envelope_digest: launch_digest, - provider_incarnation_id: launch.provider_incarnation_id.clone(), - provider_public_key: launch.provider_public_key.clone(), - projection_schema_version: plan.projection_schema_version.clone(), - chunker_id: plan.chunker_id.clone(), - embedding_provider_id: plan.embedding_provider_id.clone(), - embedding_artifact_identity: plan.embedding_model.clone(), - vector_dimensions: plan.vector_dimensions, - collection_name: workspace_coverage_execution_collection( - &plan.plan_id, - &claim.claim_id, - claim.claim_epoch, - )?, - batch_ordinal, - first_plan_ordinal: observed.first_plan_ordinal, - point_count, - cumulative_point_count: cumulative, - total_point_count: plan.expected_point_count, - point_ids, - point_bindings: observed.point_bindings, - vector_bindings: observed.vector_bindings, - observed_at_utc: chrono::Utc::now().to_rfc3339(), - observation_method: OBSERVATION_METHOD.into(), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - sign_workspace_coverage_projection_batch_checkpoint(&mut entry, provider_signing_key)?; - admit_workspace_coverage_projection_batch_checkpoint( - body_store, - coverage_store, - local_verse_store, - trusted_host, - provider_signing_key, - entry, - ) -} - -pub(crate) fn load_authenticated_current_checkpoint( - body_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - trusted_host: &HostIncarnationIdentityEntry, - claim_id: &str, - claim_epoch: u64, -) -> Result> { - let opening = coverage_store.pull_all()?; - let head_key = checkpoint_head_key(claim_id, claim_epoch); - let Some(head_env) = opening - .iter() - .find(|env| env.r#type == HEAD_TYPE && env.key == head_key) - else { - return Ok(None); - }; - let head: WorkspaceCoverageProjectionBatchCheckpointHeadEntry = decode(head_env)?; - if head.schema_version != HEAD_SCHEMA - || head.claim_id != claim_id - || head.claim_epoch != claim_epoch - || head.sequence == 0 - { - bail!("current checkpoint head identity is invalid"); - } - let event_env = find( - &opening, - WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE, - &checkpoint_key(claim_id, &head.checkpoint_id), - )?; - if envelope_digest(event_env) != head.checkpoint_envelope_digest { - bail!("current checkpoint head digest disagrees with event"); - } - let checkpoint: WorkspaceCoverageProjectionBatchCheckpointEntry = decode(event_env)?; - validate_shape(&checkpoint, true)?; - authenticate_signature(&checkpoint)?; - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - checkpoint.runtime_id.clone(), - &checkpoint.managed_process_launch_id, - trusted_host, - )?; - validate_launch(&checkpoint, &launch, &launch_digest)?; - validate_current_head_event_identity(&checkpoint, &head)?; - let body_opening = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - let binding_env = find(&body_opening, BODY_BINDING_TYPE, BODY_BINDING_KEY)?; - let body_head_env = find(&body_opening, BODY_HEAD_TYPE, BODY_HEAD_KEY)?; - let observation_env = find( - &body_opening, - BODY_OBSERVATION_TYPE, - &checkpoint.body_observation_id, - )?; - let manifest_env = find( - &body_opening, - BODY_MANIFEST_TYPE, - &checkpoint.manifest_root_sha256, - )?; - let obligation_env = find(&opening, OBLIGATION_TYPE, &checkpoint.obligation_id)?; - let plan_env = find(&opening, PLAN_TYPE, &checkpoint.plan_id)?; - let claim_env = find( - &opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&checkpoint.body_observation_id, checkpoint.body_generation), - )?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &checkpoint.attempt_id)?; - let binding: RepositoryBodyBinding = decode(binding_env)?; - let body_head: RepositoryBodyHead = decode(body_head_env)?; - let observation: RepositoryBodyObservation = decode(observation_env)?; - let manifest: RepositoryBodyManifest = decode(manifest_env)?; - let obligation: WorkspaceCoverageObligation = decode(obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(plan_env)?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_projection_claim(&claim)?; - validate_projection_attempt(&attempt)?; - validate_claim_attempt_link(&claim, &attempt)?; - validate_current_projection_binding( - &checkpoint, - CurrentProjectionBinding { - claim_status: &claim.status, - claim_id: &claim.claim_id, - claim_epoch: claim.claim_epoch, - attempt_status: &attempt.status, - attempt_id: &attempt.attempt_id, - claim_plan_id: &claim.plan_id, - attempt_plan_id: &attempt.plan_id, - plan_id: &plan.plan_id, - claim_obligation_id: &claim.obligation_id, - obligation_id: &obligation.obligation_id, - plan_obligation_id: &plan.obligation_id, - claim_body_observation_id: &claim.body_observation_id, - obligation_body_observation_id: &obligation.body_observation_id, - claim_body_generation: claim.body_generation, - obligation_body_generation: obligation.body_generation, - claim_manifest_root: &claim.manifest_root_sha256, - obligation_manifest_root: &obligation.manifest_root_sha256, - }, - )?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - let body_authority = exact_obligation_body_authority(&body_opening, &obligation)?; - validate_authority( - &checkpoint, - &binding, - binding_env, - &body_head, - body_head_env, - &observation, - observation_env, - &manifest, - manifest_env, - &obligation, - obligation_env, - &plan, - plan_env, - &claim, - claim_env, - &attempt, - attempt_env, - )?; - validate_batch_against_plan(&checkpoint, &obligation, &plan)?; - let admission = WorkspaceCoverageProjectionBatchCheckpointAdmission { - checkpoint, - checkpoint_envelope_digest: head.checkpoint_envelope_digest, - }; - let closing_body = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - for expected in body_authority { - if closing_body - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(&expected) - { - bail!("Repository Body changed while loading current workspace checkpoint"); - } - } - Ok(Some(admission)) -} - -pub(crate) fn load_authenticated_checkpoint_chain( - body_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - trusted_host: &HostIncarnationIdentityEntry, - claim_id: &str, - claim_epoch: u64, -) -> Result> { - let Some(current) = load_authenticated_current_checkpoint( - body_store, - coverage_store, - local_verse_store.as_ref(), - trusted_host, - claim_id, - claim_epoch, - )? - else { - return Ok(Vec::new()); - }; - let opening = coverage_store.pull_all()?; - let head_env = find( - &opening, - HEAD_TYPE, - &checkpoint_head_key(claim_id, claim_epoch), - )?; - let head: WorkspaceCoverageProjectionBatchCheckpointHeadEntry = decode(head_env)?; - if head.checkpoint_id != current.checkpoint.checkpoint_id - || head.checkpoint_envelope_digest != current.checkpoint_envelope_digest - { - bail!("checkpoint head changed while reconstructing authenticated chain"); - } - let body_opening = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - let binding_env = find(&body_opening, BODY_BINDING_TYPE, BODY_BINDING_KEY)?; - let body_head_env = find(&body_opening, BODY_HEAD_TYPE, BODY_HEAD_KEY)?; - let observation_env = find( - &body_opening, - BODY_OBSERVATION_TYPE, - ¤t.checkpoint.body_observation_id, - )?; - let manifest_env = find( - &body_opening, - BODY_MANIFEST_TYPE, - ¤t.checkpoint.manifest_root_sha256, - )?; - let obligation_env = find(&opening, OBLIGATION_TYPE, ¤t.checkpoint.obligation_id)?; - let plan_env = find(&opening, PLAN_TYPE, ¤t.checkpoint.plan_id)?; - let claim_env = find( - &opening, - CLAIM_TYPE, - &workspace_coverage_claim_key( - ¤t.checkpoint.body_observation_id, - current.checkpoint.body_generation, - ), - )?; - let attempt_env = find(&opening, ATTEMPT_TYPE, ¤t.checkpoint.attempt_id)?; - let binding: RepositoryBodyBinding = decode(binding_env)?; - let body_head: RepositoryBodyHead = decode(body_head_env)?; - let observation: RepositoryBodyObservation = decode(observation_env)?; - let manifest: RepositoryBodyManifest = decode(manifest_env)?; - let obligation: WorkspaceCoverageObligation = decode(obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(plan_env)?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_projection_claim(&claim)?; - validate_projection_attempt(&attempt)?; - validate_claim_attempt_link(&claim, &attempt)?; - validate_current_projection_binding( - ¤t.checkpoint, - CurrentProjectionBinding { - claim_status: &claim.status, - claim_id: &claim.claim_id, - claim_epoch: claim.claim_epoch, - attempt_status: &attempt.status, - attempt_id: &attempt.attempt_id, - claim_plan_id: &claim.plan_id, - attempt_plan_id: &attempt.plan_id, - plan_id: &plan.plan_id, - claim_obligation_id: &claim.obligation_id, - obligation_id: &obligation.obligation_id, - plan_obligation_id: &plan.obligation_id, - claim_body_observation_id: &claim.body_observation_id, - obligation_body_observation_id: &obligation.body_observation_id, - claim_body_generation: claim.body_generation, - obligation_body_generation: obligation.body_generation, - claim_manifest_root: &claim.manifest_root_sha256, - obligation_manifest_root: &obligation.manifest_root_sha256, - }, - )?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - let body_authority = exact_obligation_body_authority(&body_opening, &obligation)?; - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - current.checkpoint.runtime_id.clone(), - ¤t.checkpoint.managed_process_launch_id, - trusted_host, - )?; - - let mut reversed = Vec::new(); - let mut next_id = Some(head.checkpoint_id.clone()); - let mut next_digest = Some(head.checkpoint_envelope_digest.clone()); - let mut seen_checkpoints = std::collections::HashSet::new(); - while let (Some(id), Some(expected_digest)) = (next_id.take(), next_digest.take()) { - if !seen_checkpoints.insert(id.clone()) { - bail!("checkpoint predecessor chain contains a cycle or duplicate event"); - } - let event_env = find( - &opening, - WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE, - &checkpoint_key(claim_id, &id), - )?; - if envelope_digest(event_env) != expected_digest { - bail!("checkpoint predecessor digest disagrees with exact event envelope"); - } - let event: WorkspaceCoverageProjectionBatchCheckpointEntry = decode(event_env)?; - validate_shape(&event, true)?; - authenticate_signature(&event)?; - validate_launch(&event, &launch, &launch_digest)?; - validate_authority( - &event, - &binding, - binding_env, - &body_head, - body_head_env, - &observation, - observation_env, - &manifest, - manifest_env, - &obligation, - obligation_env, - &plan, - plan_env, - &claim, - claim_env, - &attempt, - attempt_env, - )?; - validate_batch_against_plan(&event, &obligation, &plan)?; - next_id = event.predecessor_checkpoint_id.clone(); - next_digest = event.predecessor_checkpoint_envelope_digest.clone(); - reversed.push(WorkspaceCoverageProjectionBatchCheckpointAdmission { - checkpoint: event, - checkpoint_envelope_digest: expected_digest, - }); - } - reversed.reverse(); - validate_reconstructed_chain(&reversed, &head)?; - let closing_body = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - for expected in body_authority { - if closing_body - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(&expected) - { - bail!("Repository Body changed while reconstructing workspace checkpoint chain"); - } - } - Ok(reversed) -} - -fn validate_reconstructed_chain( - chain: &[WorkspaceCoverageProjectionBatchCheckpointAdmission], - head: &WorkspaceCoverageProjectionBatchCheckpointHeadEntry, -) -> Result<()> { - let mut prior: Option<&WorkspaceCoverageProjectionBatchCheckpointEntry> = None; - let mut seen_points = std::collections::HashSet::new(); - for admission in chain { - let event = &admission.checkpoint; - let expected_sequence = match prior { - Some(p) => p - .sequence - .checked_add(1) - .ok_or_else(|| anyhow!("checkpoint sequence exhausted"))?, - None => 1, - }; - if event.sequence != expected_sequence - || event.first_plan_ordinal != prior.map_or(0, |p| p.cumulative_point_count) - || event.batch_ordinal != event.sequence - 1 - || event - .point_ids - .iter() - .any(|id| !seen_points.insert(id.clone())) - { - bail!("checkpoint chain is noncontiguous or overlaps prior sealed points"); - } - prior = Some(event); - } - if prior.map(|p| p.sequence) != Some(head.sequence) - || prior.map(|p| p.cumulative_point_count) != Some(head.cumulative_point_count) - { - bail!("checkpoint chain does not reconstruct the authenticated current head"); - } - Ok(()) -} - -#[derive(Clone, Copy)] -struct CurrentProjectionBinding<'a> { - claim_status: &'a str, - claim_id: &'a str, - claim_epoch: u64, - attempt_status: &'a str, - attempt_id: &'a str, - claim_plan_id: &'a str, - attempt_plan_id: &'a str, - plan_id: &'a str, - claim_obligation_id: &'a str, - obligation_id: &'a str, - plan_obligation_id: &'a str, - claim_body_observation_id: &'a str, - obligation_body_observation_id: &'a str, - claim_body_generation: u64, - obligation_body_generation: u64, - claim_manifest_root: &'a str, - obligation_manifest_root: &'a str, -} - -fn validate_current_projection_binding( - checkpoint: &WorkspaceCoverageProjectionBatchCheckpointEntry, - current: CurrentProjectionBinding<'_>, -) -> Result<()> { - if current.claim_status != "running" - || current.attempt_status != "running" - || checkpoint.claim_id != current.claim_id - || checkpoint.claim_epoch != current.claim_epoch - || checkpoint.attempt_id != current.attempt_id - || checkpoint.plan_id != current.claim_plan_id - || checkpoint.plan_id != current.attempt_plan_id - || checkpoint.plan_id != current.plan_id - || checkpoint.obligation_id != current.claim_obligation_id - || checkpoint.obligation_id != current.obligation_id - || current.plan_obligation_id != current.obligation_id - || checkpoint.body_observation_id != current.claim_body_observation_id - || checkpoint.body_observation_id != current.obligation_body_observation_id - || checkpoint.body_generation != current.claim_body_generation - || checkpoint.body_generation != current.obligation_body_generation - || checkpoint.manifest_root_sha256 != current.claim_manifest_root - || checkpoint.manifest_root_sha256 != current.obligation_manifest_root - { - bail!("checkpoint no longer belongs to current running Body projection authority"); - } - Ok(()) -} - -fn validate_current_head_event_identity( - checkpoint: &WorkspaceCoverageProjectionBatchCheckpointEntry, - head: &WorkspaceCoverageProjectionBatchCheckpointHeadEntry, -) -> Result<()> { - if checkpoint.claim_id != head.claim_id - || checkpoint.claim_epoch != head.claim_epoch - || checkpoint.checkpoint_id != head.checkpoint_id - || checkpoint.sequence != head.sequence - || checkpoint.cumulative_point_count != head.cumulative_point_count - || checkpoint.total_point_count != head.total_point_count - || checkpoint.collection_name != head.collection_name - { - bail!("current checkpoint head is stale or substituted"); - } - Ok(()) -} - -fn validate_observed_batch_input(observed: &ObservedWorkspaceCoverageBatchInput) -> Result<()> { - if observed.claim_id.trim().is_empty() - || observed.attempt_id.trim().is_empty() - || observed.plan_id.trim().is_empty() - || observed.point_bindings.is_empty() - || observed.point_bindings.len() > WORKSPACE_COVERAGE_BATCH_CHECKPOINT_MAX_POINTS - || observed.point_bindings.len() != observed.vector_bindings.len() - { - bail!("observed workspace coverage batch has invalid bounded cardinality"); - } - for (point, vector) in observed - .point_bindings - .iter() - .zip(&observed.vector_bindings) - { - if point.point_id.trim().is_empty() - || point.point_id != vector.point_id - || !canonical_sha256(&point.payload_sha256) - || !canonical_sha256(&vector.vector_sha256) - { - bail!("observed workspace coverage batch binding shape is invalid"); - } - } - Ok(()) -} - -pub(crate) fn sign_workspace_coverage_projection_batch_checkpoint( - entry: &mut WorkspaceCoverageProjectionBatchCheckpointEntry, - key: &SigningKey, -) -> Result<()> { - if key.verifying_key().to_bytes().as_slice() != entry.provider_public_key.as_slice() { - bail!("checkpoint signing key disagrees with provider public key"); - } - entry.provider_signature.clear(); - validate_shape(entry, false)?; - entry.provider_signature = key.sign(&signature_message(entry)?).to_bytes().to_vec(); - Ok(()) -} - -pub(crate) fn admit_workspace_coverage_projection_batch_checkpoint( - body_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - trusted_host: &HostIncarnationIdentityEntry, - provider_signing_key: &SigningKey, - entry: WorkspaceCoverageProjectionBatchCheckpointEntry, -) -> Result { - validate_shape(&entry, true)?; - authenticate_signature(&entry)?; - let (launch, launch_envelope_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store, - entry.runtime_id.clone(), - &entry.managed_process_launch_id, - trusted_host, - )?; - validate_launch(&entry, &launch, &launch_envelope_digest)?; - let opening = coverage_store.pull_all()?; - let body_opening = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - let binding_env = find(&body_opening, BODY_BINDING_TYPE, BODY_BINDING_KEY)?; - let head_env = find(&body_opening, BODY_HEAD_TYPE, BODY_HEAD_KEY)?; - let observation_env = find( - &body_opening, - BODY_OBSERVATION_TYPE, - &entry.body_observation_id, - )?; - let manifest_env = find( - &body_opening, - BODY_MANIFEST_TYPE, - &entry.manifest_root_sha256, - )?; - let obligation_env = find(&opening, OBLIGATION_TYPE, &entry.obligation_id)?; - let plan_env = find(&opening, PLAN_TYPE, &entry.plan_id)?; - let claim_env = find( - &opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&entry.body_observation_id, entry.body_generation), - )?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &entry.attempt_id)?; - let binding: RepositoryBodyBinding = decode(binding_env)?; - let body_head: RepositoryBodyHead = decode(head_env)?; - let observation: RepositoryBodyObservation = decode(observation_env)?; - let manifest: RepositoryBodyManifest = decode(manifest_env)?; - let obligation: WorkspaceCoverageObligation = decode(obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(plan_env)?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_projection_claim(&claim)?; - validate_projection_attempt(&attempt)?; - validate_claim_attempt_link(&claim, &attempt)?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - let body_authority = exact_obligation_body_authority(&body_opening, &obligation)?; - validate_authority( - &entry, - &binding, - binding_env, - &body_head, - head_env, - &observation, - observation_env, - &manifest, - manifest_env, - &obligation, - obligation_env, - &plan, - plan_env, - &claim, - claim_env, - &attempt, - attempt_env, - )?; - validate_batch_against_plan(&entry, &obligation, &plan)?; - - let event_key = checkpoint_key(&entry.claim_id, &entry.checkpoint_id); - if opening.iter().any(|env| { - env.r#type == WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE && env.key == event_key - }) { - bail!("workspace coverage checkpoint identity collision"); - } - let event_env = envelope( - WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE, - &event_key, - &entry, - )?; - let event_digest = envelope_digest(&event_env); - let head_key = checkpoint_head_key(&entry.claim_id, entry.claim_epoch); - let prior_head_env = opening - .iter() - .find(|env| env.r#type == HEAD_TYPE && env.key == head_key) - .cloned(); - let prior_head: Option = - prior_head_env.as_ref().map(decode).transpose()?; - let prior_event_env = match prior_head.as_ref() { - Some(head) => { - let predecessor_key = checkpoint_key(&head.claim_id, &head.checkpoint_id); - let predecessor_env = find( - &opening, - WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE, - &predecessor_key, - )? - .clone(); - if envelope_digest(&predecessor_env) != head.checkpoint_envelope_digest { - bail!("checkpoint head digest disagrees with predecessor event"); - } - let predecessor: WorkspaceCoverageProjectionBatchCheckpointEntry = - decode(&predecessor_env)?; - validate_shape(&predecessor, true)?; - authenticate_signature(&predecessor)?; - validate_launch(&predecessor, &launch, &launch_envelope_digest)?; - validate_predecessor_identity(&predecessor, head, &entry)?; - Some(predecessor_env) - } - None => None, - }; - validate_chain(&entry, prior_head.as_ref())?; - let next_head = WorkspaceCoverageProjectionBatchCheckpointHeadEntry { - schema_version: HEAD_SCHEMA.into(), - claim_id: entry.claim_id.clone(), - claim_epoch: entry.claim_epoch, - checkpoint_id: entry.checkpoint_id.clone(), - checkpoint_envelope_digest: event_digest, - sequence: entry.sequence, - cumulative_point_count: entry.cumulative_point_count, - total_point_count: entry.total_point_count, - collection_name: entry.collection_name.clone(), - }; - let authority = vec![ - obligation_env.clone(), - plan_env.clone(), - claim_env.clone(), - attempt_env.clone(), - ]; - let mut expected = authority.clone(); - if let Some(prior) = prior_head_env { - expected.push(prior); - } - let mut replacements = authority; - if let Some(predecessor) = prior_event_env { - expected.push(predecessor.clone()); - replacements.push(predecessor); - } - replacements.push(event_env); - replacements.push(envelope(HEAD_TYPE, &head_key, &next_head)?); - let admission = WorkspaceCoverageProjectionBatchCheckpointAdmission { - checkpoint: entry, - checkpoint_envelope_digest: next_head.checkpoint_envelope_digest, - }; - let (progress_expected, progress_replacements, progress) = - crate::workspace_coverage_projection_progress::prepare_workspace_coverage_progress_for_checkpoint( - coverage_store, - provider_signing_key, - &admission, - )?; - expected.extend(progress_expected); - replacements.extend(progress_replacements); - if !coverage_store.compare_and_swap_batch(&expected, replacements)? { - bail!("workspace coverage checkpoint lost exact coverage authority compare-and-swap"); - } - let closing_body = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - for expected in body_authority { - if closing_body - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(&expected) - { - bail!("Repository Body changed during workspace coverage checkpoint admission"); - } - } - debug_assert_eq!( - progress.completed_units, - admission.checkpoint.cumulative_point_count - ); - Ok(admission) -} - -#[allow(clippy::too_many_arguments)] -fn validate_authority( - e: &WorkspaceCoverageProjectionBatchCheckpointEntry, - binding: &RepositoryBodyBinding, - binding_env: &CultCacheEnvelope, - head: &RepositoryBodyHead, - head_env: &CultCacheEnvelope, - observation: &RepositoryBodyObservation, - observation_env: &CultCacheEnvelope, - manifest: &RepositoryBodyManifest, - manifest_env: &CultCacheEnvelope, - obligation: &WorkspaceCoverageObligation, - obligation_env: &CultCacheEnvelope, - plan: &WorkspaceCoverageProjectionPlan, - plan_env: &CultCacheEnvelope, - claim: &WorkspaceCoverageProjectionClaim, - claim_env: &CultCacheEnvelope, - attempt: &WorkspaceCoverageProjectionAttempt, - attempt_env: &CultCacheEnvelope, -) -> Result<()> { - if e.runtime_id != binding.runtime_id - || e.workspace_id != binding.workspace_id - || e.body_binding_sha256 != obligation.body_binding_sha256 - || e.body_binding_envelope_digest != envelope_digest(binding_env) - || e.body_head_envelope_digest != envelope_digest(head_env) - || e.body_observation_id != head.observation_id - || e.body_generation != head.generation - || e.manifest_root_sha256 != head.manifest_root_sha256 - || observation.observation_id != e.body_observation_id - || observation.generation != e.body_generation - || observation.manifest_root_sha256 != e.manifest_root_sha256 - || manifest.manifest_root_sha256 != e.manifest_root_sha256 - || e.body_observation_envelope_digest != envelope_digest(observation_env) - || e.body_manifest_envelope_digest != envelope_digest(manifest_env) - || obligation.obligation_id != e.obligation_id - || obligation.plan_identity(e).is_err() - || e.obligation_envelope_digest != envelope_digest(obligation_env) - || plan.plan_id != e.plan_id - || e.plan_envelope_digest != envelope_digest(plan_env) - || claim.claim_id != e.claim_id - || claim.claim_epoch != e.claim_epoch - || claim.status != "running" - || claim.plan_id != e.plan_id - || claim.attempt_id != e.attempt_id - || claim.obligation_id != e.obligation_id - || claim.body_observation_id != e.body_observation_id - || claim.body_generation != e.body_generation - || claim.manifest_root_sha256 != e.manifest_root_sha256 - || claim.executor_incarnation != e.provider_incarnation_id - || claim.managed_process_launch_id != e.managed_process_launch_id - || e.claim_envelope_digest != envelope_digest(claim_env) - || attempt.attempt_id != e.attempt_id - || attempt.claim_id != e.claim_id - || attempt.claim_epoch != e.claim_epoch - || attempt.plan_id != e.plan_id - || attempt.status != "running" - || attempt.executor_incarnation != e.provider_incarnation_id - || attempt.managed_process_launch_id != e.managed_process_launch_id - || e.attempt_envelope_digest != envelope_digest(attempt_env) - { - bail!("workspace coverage checkpoint authority is substituted or terminal"); - } - Ok(()) -} - -trait ObligationIdentity { - fn plan_identity(&self, e: &WorkspaceCoverageProjectionBatchCheckpointEntry) -> Result<()>; -} -impl ObligationIdentity for WorkspaceCoverageObligation { - fn plan_identity(&self, e: &WorkspaceCoverageProjectionBatchCheckpointEntry) -> Result<()> { - if self.runtime_id != e.runtime_id - || self.workspace_id != e.workspace_id - || self.body_observation_id != e.body_observation_id - || self.body_generation != e.body_generation - || self.manifest_root_sha256 != e.manifest_root_sha256 - { - bail!("obligation identity mismatch") - } - Ok(()) - } -} - -fn validate_batch_against_plan( - e: &WorkspaceCoverageProjectionBatchCheckpointEntry, - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, -) -> Result<()> { - if plan.obligation_id != e.obligation_id - || plan.projection_schema_version != e.projection_schema_version - || plan.chunker_id != e.chunker_id - || plan.embedding_provider_id != e.embedding_provider_id - || plan.embedding_model != e.embedding_artifact_identity - || plan.vector_dimensions != e.vector_dimensions - || plan.expected_point_count != e.total_point_count - || workspace_coverage_execution_collection(&plan.plan_id, &e.claim_id, e.claim_epoch)? - != e.collection_name - { - bail!("checkpoint plan/model identity mismatch"); - } - let start: usize = e.first_plan_ordinal.try_into()?; - let end = start - .checked_add(e.point_count.try_into()?) - .ok_or_else(|| anyhow!("batch range overflow"))?; - let planned = plan - .planned_points - .get(start..end) - .ok_or_else(|| anyhow!("checkpoint batch exceeds sealed plan"))?; - if planned - .iter() - .map(|p| p.point_id.clone()) - .collect::>() - != e.point_ids - { - bail!("checkpoint point order/range disagrees with sealed plan"); - } - for ((planned, point), vector) in planned - .iter() - .zip(&e.point_bindings) - .zip(&e.vector_bindings) - { - let expected_payload = payload_for(obligation, plan, planned); - if point.point_id != planned.point_id - || vector.point_id != planned.point_id - || point.payload_sha256 != digest_named(&expected_payload)? - || !canonical_sha256(&vector.vector_sha256) - { - bail!("checkpoint observed bindings disagree with sealed point payload/vector shape"); - } - } - Ok(()) -} - -fn validate_shape(e: &WorkspaceCoverageProjectionBatchCheckpointEntry, signed: bool) -> Result<()> { - if e.schema_version != WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_SCHEMA_VERSION - || e.sequence == 0 - || e.claim_epoch == 0 - || e.body_generation == 0 - || e.vector_dimensions == 0 - || e.total_point_count == 0 - || e.point_count == 0 - || e.point_count as usize > WORKSPACE_COVERAGE_BATCH_CHECKPOINT_MAX_POINTS - || e.point_ids.len() != e.point_count as usize - || e.point_bindings.len() != e.point_ids.len() - || e.vector_bindings.len() != e.point_ids.len() - || e.cumulative_point_count > e.total_point_count - || e.first_plan_ordinal.checked_add(e.point_count) != Some(e.cumulative_point_count) - || e.observation_method != OBSERVATION_METHOD - || e.signature_algorithm != "ed25519" - || e.provider_public_key.len() != 32 - || (signed && e.provider_signature.len() != 64) - || (!signed && !e.provider_signature.is_empty()) - { - bail!("workspace coverage checkpoint shape is invalid"); - } - if e.point_ids - .iter() - .collect::>() - .len() - != e.point_ids.len() - { - bail!("workspace coverage checkpoint point ids are not unique"); - } - for value in [ - &e.checkpoint_id, - &e.runtime_id, - &e.workspace_id, - &e.body_binding_sha256, - &e.body_observation_id, - &e.manifest_root_sha256, - &e.obligation_id, - &e.plan_id, - &e.claim_id, - &e.attempt_id, - &e.managed_process_launch_id, - &e.provider_incarnation_id, - &e.embedding_artifact_identity, - &e.collection_name, - ] { - if value.trim().is_empty() { - bail!("workspace coverage checkpoint identity is empty"); - } - } - uuid::Uuid::parse_str(&e.checkpoint_id)?; - uuid::Uuid::parse_str(&e.managed_process_launch_id)?; - uuid::Uuid::parse_str(&e.provider_incarnation_id)?; - DateTime::parse_from_rfc3339(&e.observed_at_utc)?; - for d in [ - &e.body_binding_envelope_digest, - &e.body_head_envelope_digest, - &e.body_observation_envelope_digest, - &e.body_manifest_envelope_digest, - &e.obligation_envelope_digest, - &e.plan_envelope_digest, - &e.claim_envelope_digest, - &e.attempt_envelope_digest, - &e.managed_process_launch_envelope_digest, - ] { - if !canonical_envelope_digest(d) { - bail!("checkpoint authority digest is invalid"); - } - } - match ( - &e.predecessor_checkpoint_id, - &e.predecessor_checkpoint_envelope_digest, - ) { - (None, None) if e.sequence == 1 => {} - (Some(id), Some(d)) if e.sequence > 1 && !id.is_empty() && canonical_envelope_digest(d) => { - } - _ => bail!("checkpoint predecessor evidence is partial or misplaced"), - } - Ok(()) -} - -fn validate_chain( - e: &WorkspaceCoverageProjectionBatchCheckpointEntry, - prior: Option<&WorkspaceCoverageProjectionBatchCheckpointHeadEntry>, -) -> Result<()> { - match prior { - None if e.sequence == 1 - && e.batch_ordinal == 0 - && e.first_plan_ordinal == 0 - && e.predecessor_checkpoint_id.is_none() => - { - Ok(()) - } - Some(p) - if p.schema_version == HEAD_SCHEMA - && p.claim_id == e.claim_id - && p.claim_epoch == e.claim_epoch - && p.sequence.checked_add(1) == Some(e.sequence) - && e.batch_ordinal == p.sequence - && e.first_plan_ordinal == p.cumulative_point_count - && e.predecessor_checkpoint_id.as_deref() == Some(&p.checkpoint_id) - && e.predecessor_checkpoint_envelope_digest.as_deref() - == Some(&p.checkpoint_envelope_digest) - && e.total_point_count == p.total_point_count - && e.collection_name == p.collection_name => - { - Ok(()) - } - _ => bail!("workspace coverage checkpoint chain is noncontiguous or mutable"), - } -} - -fn validate_predecessor_identity( - predecessor: &WorkspaceCoverageProjectionBatchCheckpointEntry, - head: &WorkspaceCoverageProjectionBatchCheckpointHeadEntry, - next: &WorkspaceCoverageProjectionBatchCheckpointEntry, -) -> Result<()> { - if predecessor.checkpoint_id != head.checkpoint_id - || predecessor.sequence != head.sequence - || predecessor.claim_id != head.claim_id - || predecessor.claim_epoch != head.claim_epoch - || predecessor.cumulative_point_count != head.cumulative_point_count - || predecessor.total_point_count != head.total_point_count - || predecessor.collection_name != head.collection_name - || predecessor.runtime_id != next.runtime_id - || predecessor.workspace_id != next.workspace_id - || predecessor.body_binding_sha256 != next.body_binding_sha256 - || predecessor.body_binding_envelope_digest != next.body_binding_envelope_digest - || predecessor.body_head_envelope_digest != next.body_head_envelope_digest - || predecessor.body_observation_id != next.body_observation_id - || predecessor.body_generation != next.body_generation - || predecessor.body_observation_envelope_digest != next.body_observation_envelope_digest - || predecessor.manifest_root_sha256 != next.manifest_root_sha256 - || predecessor.body_manifest_envelope_digest != next.body_manifest_envelope_digest - || predecessor.obligation_id != next.obligation_id - || predecessor.obligation_envelope_digest != next.obligation_envelope_digest - || predecessor.plan_id != next.plan_id - || predecessor.plan_envelope_digest != next.plan_envelope_digest - || predecessor.claim_id != next.claim_id - || predecessor.claim_epoch != next.claim_epoch - || predecessor.claim_envelope_digest != next.claim_envelope_digest - || predecessor.attempt_id != next.attempt_id - || predecessor.attempt_envelope_digest != next.attempt_envelope_digest - || predecessor.managed_process_launch_id != next.managed_process_launch_id - || predecessor.managed_process_launch_envelope_digest - != next.managed_process_launch_envelope_digest - || predecessor.provider_incarnation_id != next.provider_incarnation_id - || predecessor.provider_public_key != next.provider_public_key - || predecessor.projection_schema_version != next.projection_schema_version - || predecessor.chunker_id != next.chunker_id - || predecessor.embedding_provider_id != next.embedding_provider_id - || predecessor.embedding_artifact_identity != next.embedding_artifact_identity - || predecessor.vector_dimensions != next.vector_dimensions - { - bail!("checkpoint predecessor/head/claim immutable identity disagrees"); - } - Ok(()) -} - -fn validate_launch( - e: &WorkspaceCoverageProjectionBatchCheckpointEntry, - l: &WorkspaceCoverageManagedProcessLaunchEntry, - d: &str, -) -> Result<()> { - if e.managed_process_launch_id != l.launch_id - || e.managed_process_launch_envelope_digest != d - || e.runtime_id != l.runtime_id - || e.provider_incarnation_id != l.provider_incarnation_id - || e.provider_public_key != l.provider_public_key - { - bail!("checkpoint disagrees with exact managed launch") - } - Ok(()) -} -fn authenticate_signature(e: &WorkspaceCoverageProjectionBatchCheckpointEntry) -> Result<()> { - let k: [u8; 32] = e.provider_public_key.as_slice().try_into()?; - let s: [u8; 64] = e.provider_signature.as_slice().try_into()?; - VerifyingKey::from_bytes(&k)? - .verify(&signature_message(e)?, &Signature::from_bytes(&s)) - .context("checkpoint signature invalid") -} -fn signature_message(e: &WorkspaceCoverageProjectionBatchCheckpointEntry) -> Result> { - let mut u = e.clone(); - u.provider_signature.clear(); - validate_shape(&u, false)?; - let b = rmp_serde::to_vec_named(&u)?; - let mut out = SIGNATURE_DOMAIN.to_vec(); - out.extend_from_slice(&(b.len() as u64).to_be_bytes()); - out.extend(b); - Ok(out) -} -fn checkpoint_key(c: &str, id: &str) -> String { - format!("workspace-coverage/checkpoint/{c}/{id}") -} -fn checkpoint_head_key(c: &str, e: u64) -> String { - format!("workspace-coverage/checkpoint-head/{c}/{e}") -} -fn find<'a>(v: &'a [CultCacheEnvelope], t: &str, k: &str) -> Result<&'a CultCacheEnvelope> { - v.iter() - .find(|e| e.r#type == t && e.key == k) - .ok_or_else(|| anyhow!("missing authority envelope {t}/{k}")) -} -fn find_current_claim<'a>( - coverage_opening: &'a [CultCacheEnvelope], - body_opening: &[CultCacheEnvelope], -) -> Result<&'a CultCacheEnvelope> { - let head: RepositoryBodyHead = decode(find(body_opening, BODY_HEAD_TYPE, BODY_HEAD_KEY)?)?; - find( - coverage_opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&head.observation_id, head.generation), - ) -} -fn decode(e: &CultCacheEnvelope) -> Result { - Ok(rmp_serde::from_slice(&e.payload)?) -} -fn envelope(t: &str, k: &str, v: &T) -> Result { - Ok(CultCacheEnvelope { - r#type: t.into(), - key: k.into(), - payload: rmp_serde::to_vec(v)?, - stored_at: chrono::Utc::now().to_rfc3339(), - schema_id: Some(t.into()), - }) -} -fn envelope_digest(e: &CultCacheEnvelope) -> String { - let mut d = Sha256::new(); - d.update(e.r#type.as_bytes()); - d.update([0]); - d.update(e.key.as_bytes()); - d.update([0]); - d.update(&e.payload); - format!("sha256-{:x}", d.finalize()) -} -fn digest_named(v: &T) -> Result { - Ok(format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(v)?))) -} -fn canonical_sha256(v: &str) -> bool { - v.len() == 64 - && v.bytes() - .all(|b| b.is_ascii_hexdigit() && !b.is_ascii_uppercase()) -} -fn canonical_envelope_digest(v: &str) -> bool { - v.strip_prefix("sha256-").is_some_and(canonical_sha256) -} -#[cfg(test)] -mod tests { - use super::*; - fn sample(k: &SigningKey) -> WorkspaceCoverageProjectionBatchCheckpointEntry { - let mut e = WorkspaceCoverageProjectionBatchCheckpointEntry { - schema_version: WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_SCHEMA_VERSION.into(), - checkpoint_id: uuid::Uuid::new_v4().to_string(), - sequence: 1, - predecessor_checkpoint_id: None, - predecessor_checkpoint_envelope_digest: None, - runtime_id: "runtime".into(), - workspace_id: "workspace".into(), - body_binding_sha256: "body".into(), - body_binding_envelope_digest: format!("sha256-{}", "a".repeat(64)), - body_head_envelope_digest: format!("sha256-{}", "b".repeat(64)), - body_observation_id: "observation".into(), - body_generation: 1, - body_observation_envelope_digest: format!("sha256-{}", "c".repeat(64)), - manifest_root_sha256: "manifest".into(), - body_manifest_envelope_digest: format!("sha256-{}", "d".repeat(64)), - obligation_id: "obligation".into(), - obligation_envelope_digest: format!("sha256-{}", "e".repeat(64)), - plan_id: "plan".into(), - plan_envelope_digest: format!("sha256-{}", "f".repeat(64)), - claim_id: "claim".into(), - claim_epoch: 1, - claim_envelope_digest: format!("sha256-{}", "1".repeat(64)), - attempt_id: "attempt".into(), - attempt_envelope_digest: format!("sha256-{}", "2".repeat(64)), - managed_process_launch_id: uuid::Uuid::new_v4().to_string(), - managed_process_launch_envelope_digest: format!("sha256-{}", "3".repeat(64)), - provider_incarnation_id: uuid::Uuid::new_v4().to_string(), - provider_public_key: k.verifying_key().to_bytes().to_vec(), - projection_schema_version: "projection".into(), - chunker_id: "chunker".into(), - embedding_provider_id: "provider".into(), - embedding_artifact_identity: "model".into(), - vector_dimensions: 3, - collection_name: "collection".into(), - batch_ordinal: 0, - first_plan_ordinal: 0, - point_count: 1, - cumulative_point_count: 1, - total_point_count: 2, - point_ids: vec!["point".into()], - point_bindings: vec![WorkspaceCoveragePointBinding { - point_id: "point".into(), - payload_sha256: "a".repeat(64), - }], - vector_bindings: vec![WorkspaceCoverageVectorBinding { - point_id: "point".into(), - vector_sha256: "b".repeat(64), - }], - observed_at_utc: "2026-07-17T00:00:00Z".into(), - observation_method: OBSERVATION_METHOD.into(), - provider_signature: vec![], - signature_algorithm: "ed25519".into(), - }; - sign_workspace_coverage_projection_batch_checkpoint(&mut e, k).unwrap(); - e - } - #[test] - fn shape_signature_and_genesis_are_strict() { - let k = SigningKey::from_bytes(&[7; 32]); - let e = sample(&k); - authenticate_signature(&e).unwrap(); - validate_chain(&e, None).unwrap(); - let mut bad = e.clone(); - bad.sequence = 2; - assert!(validate_chain(&bad, None).is_err()); - bad = e.clone(); - bad.provider_signature[0] ^= 1; - assert!(authenticate_signature(&bad).is_err()); - } - #[test] - fn gaps_overlap_reorder_and_mutable_head_are_refused() { - let k = SigningKey::from_bytes(&[7; 32]); - let mut e = sample(&k); - e.sequence = 2; - e.batch_ordinal = 1; - e.first_plan_ordinal = 1; - e.cumulative_point_count = 2; - e.predecessor_checkpoint_id = Some("prior".into()); - e.predecessor_checkpoint_envelope_digest = Some(format!("sha256-{}", "9".repeat(64))); - let h = WorkspaceCoverageProjectionBatchCheckpointHeadEntry { - schema_version: HEAD_SCHEMA.into(), - claim_id: e.claim_id.clone(), - claim_epoch: 1, - checkpoint_id: "prior".into(), - checkpoint_envelope_digest: e.predecessor_checkpoint_envelope_digest.clone().unwrap(), - sequence: 1, - cumulative_point_count: 1, - total_point_count: 2, - collection_name: "collection".into(), - }; - assert!(validate_chain(&e, Some(&h)).is_ok()); - for m in ["gap", "overlap", "total", "collection"] { - let mut x = e.clone(); - match m { - "gap" => x.first_plan_ordinal = 2, - "overlap" => x.batch_ordinal = 0, - "total" => x.total_point_count = 3, - _ => x.collection_name.push('x'), - }; - assert!(validate_chain(&x, Some(&h)).is_err(), "{m}"); - } - } - #[test] - fn bounded_batch_and_identity_collision_are_refused() { - let k = SigningKey::from_bytes(&[7; 32]); - let mut e = sample(&k); - e.point_count = 129; - assert!(validate_shape(&e, true).is_err()); - let existing = e.clone(); - let mut collision = e; - collision.collection_name.push('x'); - assert_ne!(existing, collision); - assert_eq!( - checkpoint_key(&existing.claim_id, &existing.checkpoint_id), - checkpoint_key(&collision.claim_id, &collision.checkpoint_id) - ); - } - #[test] - fn nonlexical_plan_order_and_arbitrary_canonical_vector_hash_are_shape_valid() { - let k = SigningKey::from_bytes(&[7; 32]); - let mut e = sample(&k); - e.point_count = 2; - e.cumulative_point_count = 2; - e.point_ids = vec!["z-plan-first".into(), "a-plan-second".into()]; - e.point_bindings = e - .point_ids - .iter() - .map(|id| WorkspaceCoveragePointBinding { - point_id: id.clone(), - payload_sha256: "a".repeat(64), - }) - .collect(); - e.vector_bindings = vec![ - WorkspaceCoverageVectorBinding { - point_id: e.point_ids[0].clone(), - vector_sha256: "0123456789abcdef".repeat(4), - }, - WorkspaceCoverageVectorBinding { - point_id: e.point_ids[1].clone(), - vector_sha256: "fedcba9876543210".repeat(4), - }, - ]; - e.provider_signature.clear(); - sign_workspace_coverage_projection_batch_checkpoint(&mut e, &k).unwrap(); - assert!(validate_shape(&e, true).is_ok()); - } - #[test] - fn checked_arithmetic_refuses_maximum_overflow() { - let k = SigningKey::from_bytes(&[7; 32]); - let mut e = sample(&k); - e.first_plan_ordinal = u64::MAX; - e.cumulative_point_count = u64::MAX; - assert!(validate_shape(&e, true).is_err()); - let head = WorkspaceCoverageProjectionBatchCheckpointHeadEntry { - schema_version: HEAD_SCHEMA.into(), - claim_id: e.claim_id.clone(), - claim_epoch: e.claim_epoch, - checkpoint_id: "prior".into(), - checkpoint_envelope_digest: format!("sha256-{}", "9".repeat(64)), - sequence: u64::MAX, - cumulative_point_count: 1, - total_point_count: e.total_point_count, - collection_name: e.collection_name.clone(), - }; - e.sequence = 1; - assert!(validate_chain(&e, Some(&head)).is_err()); - } - #[test] - fn high_level_builder_input_refuses_caller_identity_and_binding_substitution() { - let valid = ObservedWorkspaceCoverageBatchInput { - claim_id: "claim".into(), - attempt_id: "attempt".into(), - plan_id: "plan".into(), - first_plan_ordinal: 0, - point_bindings: vec![WorkspaceCoveragePointBinding { - point_id: "sealed-point".into(), - payload_sha256: "a".repeat(64), - }], - vector_bindings: vec![WorkspaceCoverageVectorBinding { - point_id: "sealed-point".into(), - vector_sha256: "b".repeat(64), - }], - }; - validate_observed_batch_input(&valid).unwrap(); - for mutation in ["claim", "point", "payload", "vector", "empty"] { - let mut alien = valid.clone(); - match mutation { - "claim" => alien.claim_id.clear(), - "point" => alien.vector_bindings[0].point_id = "substituted".into(), - "payload" => alien.point_bindings[0].payload_sha256 = "not-a-digest".into(), - "vector" => alien.vector_bindings[0].vector_sha256 = "not-a-digest".into(), - _ => { - alien.point_bindings.clear(); - alien.vector_bindings.clear(); - } - } - assert!(validate_observed_batch_input(&alien).is_err(), "{mutation}"); - } - } - #[test] - fn authenticated_head_identity_refuses_stale_or_substituted_event() { - let k = SigningKey::from_bytes(&[7; 32]); - let event = sample(&k); - let head = WorkspaceCoverageProjectionBatchCheckpointHeadEntry { - schema_version: HEAD_SCHEMA.into(), - claim_id: event.claim_id.clone(), - claim_epoch: event.claim_epoch, - checkpoint_id: event.checkpoint_id.clone(), - checkpoint_envelope_digest: format!("sha256-{}", "9".repeat(64)), - sequence: event.sequence, - cumulative_point_count: event.cumulative_point_count, - total_point_count: event.total_point_count, - collection_name: event.collection_name.clone(), - }; - validate_current_head_event_identity(&event, &head).unwrap(); - for mutation in ["sequence", "count", "claim", "checkpoint", "collection"] { - let mut stale = head.clone(); - match mutation { - "sequence" => stale.sequence += 1, - "count" => stale.cumulative_point_count += 1, - "claim" => stale.claim_id.push('x'), - "checkpoint" => stale.checkpoint_id.push('x'), - _ => stale.collection_name.push('x'), - } - assert!( - validate_current_head_event_identity(&event, &stale).is_err(), - "{mutation}" - ); - } - } - #[test] - fn reconstructed_chain_rejects_corrupted_earlier_batch_and_overlap() { - let k = SigningKey::from_bytes(&[7; 32]); - let first = sample(&k); - let mut second = first.clone(); - second.checkpoint_id = uuid::Uuid::new_v4().to_string(); - second.sequence = 2; - second.batch_ordinal = 1; - second.first_plan_ordinal = 1; - second.cumulative_point_count = 2; - second.point_ids = vec!["point-2".into()]; - second.point_bindings[0].point_id = "point-2".into(); - second.vector_bindings[0].point_id = "point-2".into(); - second.predecessor_checkpoint_id = Some(first.checkpoint_id.clone()); - second.predecessor_checkpoint_envelope_digest = Some(format!("sha256-{}", "8".repeat(64))); - let chain = vec![ - WorkspaceCoverageProjectionBatchCheckpointAdmission { - checkpoint: first.clone(), - checkpoint_envelope_digest: format!("sha256-{}", "8".repeat(64)), - }, - WorkspaceCoverageProjectionBatchCheckpointAdmission { - checkpoint: second.clone(), - checkpoint_envelope_digest: format!("sha256-{}", "9".repeat(64)), - }, - ]; - let head = WorkspaceCoverageProjectionBatchCheckpointHeadEntry { - schema_version: HEAD_SCHEMA.into(), - claim_id: second.claim_id.clone(), - claim_epoch: second.claim_epoch, - checkpoint_id: second.checkpoint_id.clone(), - checkpoint_envelope_digest: chain[1].checkpoint_envelope_digest.clone(), - sequence: 2, - cumulative_point_count: 2, - total_point_count: 2, - collection_name: second.collection_name.clone(), - }; - validate_reconstructed_chain(&chain, &head).unwrap(); - let mut corrupt = chain.clone(); - corrupt[0].checkpoint.sequence = 2; - assert!(validate_reconstructed_chain(&corrupt, &head).is_err()); - let mut overlap = chain.clone(); - overlap[1].checkpoint.point_ids[0] = overlap[0].checkpoint.point_ids[0].clone(); - assert!(validate_reconstructed_chain(&overlap, &head).is_err()); - } - #[test] - fn current_body_projection_rejects_historical_or_terminal_checkpoint_authority() { - let k = SigningKey::from_bytes(&[7; 32]); - let event = sample(&k); - let current = CurrentProjectionBinding { - claim_status: "running", - claim_id: &event.claim_id, - claim_epoch: event.claim_epoch, - attempt_status: "running", - attempt_id: &event.attempt_id, - claim_plan_id: &event.plan_id, - attempt_plan_id: &event.plan_id, - plan_id: &event.plan_id, - claim_obligation_id: &event.obligation_id, - obligation_id: &event.obligation_id, - plan_obligation_id: &event.obligation_id, - claim_body_observation_id: &event.body_observation_id, - obligation_body_observation_id: &event.body_observation_id, - claim_body_generation: event.body_generation, - obligation_body_generation: event.body_generation, - claim_manifest_root: &event.manifest_root_sha256, - obligation_manifest_root: &event.manifest_root_sha256, - }; - validate_current_projection_binding(&event, current).unwrap(); - for mutation in [ - "prior-generation", - "terminal-claim", - "terminal-attempt", - "replaced-claim", - "changed-plan", - "changed-obligation", - "changed-manifest", - ] { - let mut stale = current; - match mutation { - "prior-generation" => stale.obligation_body_generation += 1, - "terminal-claim" => stale.claim_status = "succeeded", - "terminal-attempt" => stale.attempt_status = "failed", - "replaced-claim" => stale.claim_id = "replacement-claim", - "changed-plan" => stale.plan_id = "replacement-plan", - "changed-obligation" => stale.obligation_id = "replacement-obligation", - _ => stale.obligation_manifest_root = "replacement-manifest", - } - assert!( - validate_current_projection_binding(&event, stale).is_err(), - "{mutation}" - ); - } - } - #[test] - fn authority_model_collection_and_total_are_signed() { - let k = SigningKey::from_bytes(&[7; 32]); - let e = sample(&k); - for m in ["body", "plan", "model", "collection", "total", "launch"] { - let mut x = e.clone(); - match m { - "body" => x.body_generation += 1, - "plan" => x.plan_id.push('x'), - "model" => x.embedding_artifact_identity.push('x'), - "collection" => x.collection_name.push('x'), - "total" => x.total_point_count += 1, - _ => { - x.managed_process_launch_envelope_digest = format!("sha256-{}", "4".repeat(64)) - } - }; - assert!(authenticate_signature(&x).is_err(), "{m}"); - } - } -} diff --git a/epiphany-core/src/workspace_coverage_projection_progress.rs b/epiphany-core/src/workspace_coverage_projection_progress.rs deleted file mode 100644 index f41ce91c..00000000 --- a/epiphany-core/src/workspace_coverage_projection_progress.rs +++ /dev/null @@ -1,1193 +0,0 @@ -use crate::workspace_coverage_process_documents::authenticate_workspace_coverage_managed_process_launch_with_envelope_digest; -use crate::workspace_coverage_projection_batch_checkpoint::{ - WorkspaceCoverageProjectionBatchCheckpointAdmission, load_authenticated_current_checkpoint, -}; -use crate::workspace_coverage_projector::{ - ATTEMPT_TYPE, CHUNKER_ID, CLAIM_TYPE, OBLIGATION_TYPE, PLAN_TYPE, PROJECTION_SCHEMA, - WorkspaceCoverageProjectionAttempt, WorkspaceCoverageProjectionClaim, - exact_obligation_body_authority, validate_claim_attempt_link, validate_projection_attempt, - validate_projection_claim, workspace_coverage_claim_key, -}; -use crate::workspace_retrieval_coverage::{ - WorkspaceCoverageObligation, WorkspaceCoverageProjectionPlan, - validate_workspace_coverage_projection_plan, -}; -use crate::{ - BODY_HEAD_KEY, BODY_HEAD_TYPE, HostIncarnationIdentityEntry, RepositoryBodyHead, - WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, WorkspaceCoverageManagedProcessLaunchEntry, - WorkspaceCoveragePolicy, authenticate_workspace_coverage_managed_process_launch, -}; -use anyhow::{Context, Result, anyhow, bail}; -use chrono::DateTime; -use cultcache_rs::{ - CacheBackingStore, CultCacheEnvelope, DatabaseEntry, OwnedRedbMessagePackBackingStore, - SingleFileMessagePackBackingStore, -}; -use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; -use serde::Serialize; -use sha2::Digest; -use std::path::Path; - -pub const WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE: &str = - "epiphany.workspace_coverage.projection_progress"; -pub const WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION: &str = - "epiphany.workspace_coverage.projection_progress.v0"; -const PROGRESS_DOMAIN: &[u8] = b"epiphany.workspace-coverage.projection-progress.v0\0"; - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.workspace_coverage.projection_progress", - schema = "WorkspaceCoverageProjectionProgressEntry" -)] -pub struct WorkspaceCoverageProjectionProgressEntry { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub progress_id: String, - #[cultcache(key = 2)] - pub runtime_id: String, - #[cultcache(key = 3)] - pub launch_id: String, - #[cultcache(key = 4)] - pub launch_envelope_digest: String, - #[cultcache(key = 5)] - pub provider_incarnation_id: String, - #[cultcache(key = 6)] - pub provider_public_key: Vec, - #[cultcache(key = 7)] - pub claim_id: String, - #[cultcache(key = 8)] - pub claim_epoch: u64, - #[cultcache(key = 9)] - pub attempt_id: String, - #[cultcache(key = 10)] - pub plan_id: String, - #[cultcache(key = 11)] - pub body_observation_id: String, - #[cultcache(key = 12)] - pub body_generation: u64, - #[cultcache(key = 13)] - pub embedding_artifact_identity: String, - #[cultcache(key = 14)] - pub embedding_dimensions: u32, - #[cultcache(key = 15)] - pub phase: String, - #[cultcache(key = 16)] - pub status: String, - #[cultcache(key = 17)] - pub completed_units: u64, - #[cultcache(key = 18)] - pub total_units: u64, - #[cultcache(key = 19)] - pub unit_kind: String, - #[cultcache(key = 20)] - pub operation_started_at_utc: String, - #[cultcache(key = 21)] - /// Provider-observed operation timeout. This is telemetry, not Body policy - /// or deployment authority; consumers must not use it to authorize work. - pub operation_timeout_ms: u64, - #[cultcache(key = 22)] - pub observed_at_utc: String, - #[cultcache(key = 23)] - pub last_advanced_at_utc: String, - #[cultcache(key = 24)] - pub sequence: u64, - /// Reference to a separately authenticated durable batch checkpoint. This - /// event chain binds the reference; it does not prove checkpoint storage, - /// contents, durability, or readiness. - #[cultcache(key = 25, default)] - pub checkpoint_id: Option, - #[cultcache(key = 26, default)] - pub checkpoint_binding_sha256: Option, - #[cultcache(key = 27)] - pub provider_signature: Vec, - #[cultcache(key = 28)] - pub signature_algorithm: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageAdvancingAuthority { - pub progress_id: String, - pub checkpoint_id: String, - pub checkpoint_binding_sha256: String, - pub claim_id: String, - pub claim_epoch: u64, - pub plan_id: String, - pub completed_units: u64, - pub total_units: u64, - pub last_advanced_at_utc: String, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct ProgressStatement<'a> { - schema_version: &'a str, - progress_id: &'a str, - runtime_id: &'a str, - launch_id: &'a str, - launch_envelope_digest: &'a str, - provider_incarnation_id: &'a str, - provider_public_key: &'a [u8], - claim_id: &'a str, - claim_epoch: u64, - attempt_id: &'a str, - plan_id: &'a str, - body_observation_id: &'a str, - body_generation: u64, - embedding_artifact_identity: &'a str, - embedding_dimensions: u32, - phase: &'a str, - status: &'a str, - completed_units: u64, - total_units: u64, - unit_kind: &'a str, - operation_started_at_utc: &'a str, - operation_timeout_ms: u64, - observed_at_utc: &'a str, - last_advanced_at_utc: &'a str, - sequence: u64, - checkpoint_id: &'a Option, - checkpoint_binding_sha256: &'a Option, - signature_algorithm: &'a str, -} - -pub(crate) fn workspace_coverage_projection_progress_statement( - entry: &WorkspaceCoverageProjectionProgressEntry, -) -> Result> { - let mut unsigned = entry.clone(); - unsigned.provider_signature.clear(); - validate_shape(&unsigned, false)?; - Ok(rmp_serde::to_vec_named(&ProgressStatement { - schema_version: &entry.schema_version, - progress_id: &entry.progress_id, - runtime_id: &entry.runtime_id, - launch_id: &entry.launch_id, - launch_envelope_digest: &entry.launch_envelope_digest, - provider_incarnation_id: &entry.provider_incarnation_id, - provider_public_key: &entry.provider_public_key, - claim_id: &entry.claim_id, - claim_epoch: entry.claim_epoch, - attempt_id: &entry.attempt_id, - plan_id: &entry.plan_id, - body_observation_id: &entry.body_observation_id, - body_generation: entry.body_generation, - embedding_artifact_identity: &entry.embedding_artifact_identity, - embedding_dimensions: entry.embedding_dimensions, - phase: &entry.phase, - status: &entry.status, - completed_units: entry.completed_units, - total_units: entry.total_units, - unit_kind: &entry.unit_kind, - operation_started_at_utc: &entry.operation_started_at_utc, - operation_timeout_ms: entry.operation_timeout_ms, - observed_at_utc: &entry.observed_at_utc, - last_advanced_at_utc: &entry.last_advanced_at_utc, - sequence: entry.sequence, - checkpoint_id: &entry.checkpoint_id, - checkpoint_binding_sha256: &entry.checkpoint_binding_sha256, - signature_algorithm: &entry.signature_algorithm, - })?) -} - -pub(crate) fn sign_workspace_coverage_projection_progress( - entry: &mut WorkspaceCoverageProjectionProgressEntry, - key: &SigningKey, -) -> Result<()> { - if key.verifying_key().to_bytes().as_slice() != entry.provider_public_key.as_slice() { - bail!("provider signing key disagrees with progress public key"); - } - entry.provider_signature.clear(); - let statement = workspace_coverage_projection_progress_statement(entry)?; - entry.provider_signature = key.sign(&provider_message(&statement)).to_bytes().to_vec(); - Ok(()) -} - -pub(crate) fn publish_workspace_coverage_progress_genesis( - body_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - runtime_id: &str, - trusted_host: &HostIncarnationIdentityEntry, - provider_signing_key: &SigningKey, - operation_timeout_ms: u64, -) -> Result { - if operation_timeout_ms == 0 { - bail!("workspace coverage progress operation timeout must be positive"); - } - let opening = coverage_store.pull_all()?; - let body_opening = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - let claim_env = find_current_claim(&opening, &body_opening)?; - let claim: WorkspaceCoverageProjectionClaim = rmp_serde::from_slice(&claim_env.payload)?; - let attempt_env = find_authority(&opening, ATTEMPT_TYPE, &claim.attempt_id)?; - let attempt: WorkspaceCoverageProjectionAttempt = rmp_serde::from_slice(&attempt_env.payload)?; - validate_projection_claim(&claim)?; - validate_projection_attempt(&attempt)?; - validate_claim_attempt_link(&claim, &attempt)?; - if claim.status != "running" { - bail!("workspace coverage progress genesis requires running claim authority"); - } - let obligation_env = find_authority(&opening, OBLIGATION_TYPE, &claim.obligation_id)?; - let plan_env = find_authority(&opening, PLAN_TYPE, &claim.plan_id)?; - let obligation: WorkspaceCoverageObligation = rmp_serde::from_slice(&obligation_env.payload)?; - let plan: WorkspaceCoverageProjectionPlan = rmp_serde::from_slice(&plan_env.payload)?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - let body_authority = exact_obligation_body_authority(&body_opening, &obligation)?; - let (launch, launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id, - &claim.managed_process_launch_id, - trusted_host, - )?; - if launch.provider_incarnation_id != claim.executor_incarnation - || launch.provider_daemon_id != claim.executor_id - || provider_signing_key.verifying_key().to_bytes().as_slice() - != launch.provider_public_key.as_slice() - || obligation.runtime_id != runtime_id - { - bail!("workspace coverage progress genesis signer/launch/Body authority disagrees"); - } - if load_latest_workspace_coverage_projection_progress( - coverage_store, - &launch.launch_id, - &claim.claim_id, - )? - .is_some() - { - bail!("workspace coverage progress genesis already exists"); - } - let now = chrono::Utc::now().to_rfc3339(); - let mut entry = WorkspaceCoverageProjectionProgressEntry { - schema_version: WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION.into(), - progress_id: uuid::Uuid::new_v4().to_string(), - runtime_id: runtime_id.into(), - launch_id: launch.launch_id.clone(), - launch_envelope_digest: launch_digest, - provider_incarnation_id: launch.provider_incarnation_id.clone(), - provider_public_key: launch.provider_public_key.clone(), - claim_id: claim.claim_id, - claim_epoch: claim.claim_epoch, - attempt_id: attempt.attempt_id, - plan_id: plan.plan_id, - body_observation_id: obligation.body_observation_id.clone(), - body_generation: obligation.body_generation, - embedding_artifact_identity: plan.embedding_model, - embedding_dimensions: plan.vector_dimensions, - phase: "preparing".into(), - status: "warming".into(), - completed_units: 0, - total_units: plan.expected_point_count, - unit_kind: "points".into(), - operation_started_at_utc: now.clone(), - operation_timeout_ms, - observed_at_utc: now.clone(), - last_advanced_at_utc: now, - sequence: 1, - checkpoint_id: None, - checkpoint_binding_sha256: None, - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - sign_workspace_coverage_projection_progress(&mut entry, provider_signing_key)?; - let published = write_workspace_coverage_projection_progress(coverage_store, entry)?; - let closing_body = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - for expected in body_authority { - if closing_body - .iter() - .find(|entry| entry.r#type == expected.r#type && entry.key == expected.key) - != Some(&expected) - { - bail!("Repository Body changed during workspace coverage progress genesis"); - } - } - Ok(published) -} - -pub(crate) fn prepare_workspace_coverage_progress_for_checkpoint( - coverage_store: &OwnedRedbMessagePackBackingStore, - provider_signing_key: &SigningKey, - admission: &WorkspaceCoverageProjectionBatchCheckpointAdmission, -) -> Result<( - Vec, - Vec, - WorkspaceCoverageProjectionProgressEntry, -)> { - let checkpoint = &admission.checkpoint; - let prior_key = latest_key(&checkpoint.managed_process_launch_id, &checkpoint.claim_id); - let opening = coverage_store.pull_all()?; - let prior_env = opening - .iter() - .find(|env| { - env.r#type == WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE && env.key == prior_key - }) - .cloned() - .ok_or_else(|| anyhow!("checkpoint progress requires canonical genesis"))?; - let prior: WorkspaceCoverageProjectionProgressEntry = decode(&prior_env)?; - let expected_sequence = checkpoint - .sequence - .checked_add(1) - .ok_or_else(|| anyhow!("checkpoint sequence exhausted"))?; - if prior.sequence != checkpoint.sequence - || checkpoint.cumulative_point_count <= prior.completed_units - { - bail!("checkpoint progress does not durably advance completed units"); - } - let now = chrono::Utc::now().to_rfc3339(); - let mut entry = WorkspaceCoverageProjectionProgressEntry { - schema_version: WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION.into(), - progress_id: uuid::Uuid::new_v4().to_string(), - runtime_id: checkpoint.runtime_id.clone(), - launch_id: checkpoint.managed_process_launch_id.clone(), - launch_envelope_digest: checkpoint.managed_process_launch_envelope_digest.clone(), - provider_incarnation_id: checkpoint.provider_incarnation_id.clone(), - provider_public_key: checkpoint.provider_public_key.clone(), - claim_id: checkpoint.claim_id.clone(), - claim_epoch: checkpoint.claim_epoch, - attempt_id: checkpoint.attempt_id.clone(), - plan_id: checkpoint.plan_id.clone(), - body_observation_id: checkpoint.body_observation_id.clone(), - body_generation: checkpoint.body_generation, - embedding_artifact_identity: checkpoint.embedding_artifact_identity.clone(), - embedding_dimensions: checkpoint.vector_dimensions, - phase: "projecting".into(), - status: "warming".into(), - completed_units: checkpoint.cumulative_point_count, - total_units: checkpoint.total_point_count, - unit_kind: "points".into(), - operation_started_at_utc: prior.operation_started_at_utc.clone(), - operation_timeout_ms: prior.operation_timeout_ms, - observed_at_utc: now.clone(), - last_advanced_at_utc: now, - sequence: expected_sequence, - checkpoint_id: Some(checkpoint.checkpoint_id.clone()), - checkpoint_binding_sha256: Some(admission.checkpoint_envelope_digest.clone()), - provider_signature: Vec::new(), - signature_algorithm: "ed25519".into(), - }; - sign_workspace_coverage_projection_progress(&mut entry, provider_signing_key)?; - validate_shape(&entry, true)?; - validate_transition(&prior, &entry)?; - let event_key = progress_key(&entry.progress_id); - let latest_key = latest_key(&entry.launch_id, &entry.claim_id); - let expected = vec![prior_env]; - let replacements = vec![ - progress_envelope(&event_key, &entry)?, - progress_envelope(&latest_key, &entry)?, - ]; - Ok((expected, replacements, entry)) -} - -fn checkpoint_progress_alignment( - progress: &WorkspaceCoverageProjectionProgressEntry, - admission: &WorkspaceCoverageProjectionBatchCheckpointAdmission, -) -> Result<()> { - let checkpoint = &admission.checkpoint; - checkpoint_progress_binding_alignment( - progress, - checkpoint.sequence, - &checkpoint.checkpoint_id, - &admission.checkpoint_envelope_digest, - checkpoint.cumulative_point_count, - ) -} - -fn checkpoint_progress_binding_alignment( - progress: &WorkspaceCoverageProjectionProgressEntry, - checkpoint_sequence: u64, - checkpoint_id: &str, - checkpoint_digest: &str, - cumulative_point_count: u64, -) -> Result<()> { - let expected = checkpoint_sequence - .checked_add(1) - .ok_or_else(|| anyhow!("checkpoint sequence exhausted"))?; - if progress.sequence == expected - && progress.checkpoint_id.as_deref() == Some(checkpoint_id) - && progress.checkpoint_binding_sha256.as_deref() == Some(checkpoint_digest) - && progress.completed_units == cumulative_point_count - { - return Ok(()); - } - bail!("progress does not map exactly to the authenticated current checkpoint") -} - -pub(crate) fn write_workspace_coverage_projection_progress( - store: &OwnedRedbMessagePackBackingStore, - entry: WorkspaceCoverageProjectionProgressEntry, -) -> Result { - validate_shape(&entry, true)?; - verify_signature(&entry)?; - let opening = store.pull_all()?; - let event_key = progress_key(&entry.progress_id); - if let Some(existing_env) = opening.iter().find(|env| { - env.r#type == WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE && env.key == event_key - }) { - let existing: WorkspaceCoverageProjectionProgressEntry = decode(existing_env)?; - if existing_event_is_idempotent(&existing, &entry)? { - return Ok(existing); - } - } - let latest_key = latest_key(&entry.launch_id, &entry.claim_id); - let latest = opening - .iter() - .find(|env| { - env.r#type == WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE && env.key == latest_key - }) - .cloned(); - let mut expected = Vec::new(); - if let Some(envelope) = latest.as_ref() { - let prior: WorkspaceCoverageProjectionProgressEntry = - rmp_serde::from_slice(&envelope.payload)?; - validate_transition(&prior, &entry)?; - expected.push(envelope.clone()); - } else if entry.sequence != 1 { - bail!("first workspace coverage progress sequence must be one"); - } - let replacements = vec![ - progress_envelope(&event_key, &entry)?, - progress_envelope(&latest_key, &entry)?, - ]; - if !store.compare_and_swap_batch(&expected, replacements)? { - bail!("workspace coverage progress lost exact launch/claim latest compare-and-swap"); - } - Ok(entry) -} - -pub fn load_workspace_coverage_projection_progress( - store: &OwnedRedbMessagePackBackingStore, - progress_id: &str, -) -> Result> { - require("progress id", progress_id)?; - load_progress(store, &progress_key(progress_id)) -} - -pub fn load_latest_workspace_coverage_projection_progress( - store: &OwnedRedbMessagePackBackingStore, - launch_id: &str, - claim_id: &str, -) -> Result> { - require("launch id", launch_id)?; - require("claim id", claim_id)?; - load_progress(store, &latest_key(launch_id, claim_id)) -} - -pub fn authenticate_workspace_coverage_projection_progress( - store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - runtime_id: &str, - progress_id: &str, - host: &HostIncarnationIdentityEntry, -) -> Result { - let entry = load_workspace_coverage_projection_progress(store, progress_id)? - .ok_or_else(|| anyhow!("workspace coverage progress is absent"))?; - let launch = authenticate_workspace_coverage_managed_process_launch( - local_verse_store.as_ref(), - runtime_id, - &entry.launch_id, - host, - )?; - let (_, digest) = authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - local_verse_store.as_ref(), - runtime_id, - &entry.launch_id, - host, - )?; - authenticate_against_launch(&entry, &launch, &digest)?; - Ok(entry) -} - -/// Authenticates durable, current, nonterminal workspace advancement. -/// Provider telemetry timeouts and heartbeat timestamps are intentionally not -/// consulted here. The supervisor separately joins this evidence to the exact -/// live managed process and applies its own no-advance lease. -pub fn authenticate_current_workspace_coverage_advancement( - body_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - local_verse_store: impl AsRef, - runtime_id: &str, - launch_id: &str, - host: &HostIncarnationIdentityEntry, - observed_at: chrono::DateTime, - no_advance_lease: chrono::Duration, -) -> Result> { - if no_advance_lease <= chrono::Duration::zero() { - bail!("workspace coverage no-advance lease must be positive"); - } - let opening = coverage_store.pull_all()?; - let body_opening = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - let claim: WorkspaceCoverageProjectionClaim = - decode(find_current_claim(&opening, &body_opening)?)?; - validate_projection_claim(&claim)?; - let attempt: WorkspaceCoverageProjectionAttempt = - decode(find_authority(&opening, ATTEMPT_TYPE, &claim.attempt_id)?)?; - validate_projection_attempt(&attempt)?; - validate_claim_attempt_link(&claim, &attempt)?; - if claim.status != "running" || attempt.status != "running" { - return Ok(None); - } - let obligation: WorkspaceCoverageObligation = decode(find_authority( - &opening, - OBLIGATION_TYPE, - &claim.obligation_id, - )?)?; - let plan: WorkspaceCoverageProjectionPlan = - decode(find_authority(&opening, PLAN_TYPE, &claim.plan_id)?)?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - let body_authority = exact_obligation_body_authority(&body_opening, &obligation)?; - let policy = - WorkspaceCoveragePolicy::bounded_regular_files_v0(WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES)?; - let policy_sha256 = format!( - "{:x}", - sha2::Sha256::digest(rmp_serde::to_vec_named(&policy).map_err(|error| anyhow!(error))?) - ); - if obligation.policy_id != policy.policy_id - || obligation.policy_sha256 != policy_sha256 - || plan.projection_schema_version != PROJECTION_SCHEMA - || plan.chunker_id != CHUNKER_ID - { - return Ok(None); - } - - let Some(latest) = load_latest_workspace_coverage_projection_progress( - coverage_store, - launch_id, - &claim.claim_id, - )? - else { - return Ok(None); - }; - let progress = authenticate_workspace_coverage_projection_progress( - coverage_store, - local_verse_store.as_ref(), - runtime_id, - &latest.progress_id, - host, - )?; - if progress.status != "warming" - || progress.completed_units == 0 - || progress.launch_id != launch_id - || progress.claim_id != claim.claim_id - || progress.claim_epoch != claim.claim_epoch - || progress.attempt_id != attempt.attempt_id - || progress.plan_id != plan.plan_id - || progress.body_observation_id != obligation.body_observation_id - || progress.body_generation != obligation.body_generation - { - return Ok(None); - } - let Some(checkpoint) = load_authenticated_current_checkpoint( - body_store, - coverage_store, - local_verse_store.as_ref(), - host, - &claim.claim_id, - claim.claim_epoch, - )? - else { - return Ok(None); - }; - checkpoint_progress_alignment(&progress, &checkpoint)?; - if !progress_is_within_no_advance_lease( - &progress.last_advanced_at_utc, - observed_at, - no_advance_lease, - )? { - return Ok(None); - } - let authority = WorkspaceCoverageAdvancingAuthority { - progress_id: progress.progress_id, - checkpoint_id: checkpoint.checkpoint.checkpoint_id, - checkpoint_binding_sha256: checkpoint.checkpoint_envelope_digest, - claim_id: claim.claim_id, - claim_epoch: claim.claim_epoch, - plan_id: plan.plan_id, - completed_units: progress.completed_units, - total_units: progress.total_units, - last_advanced_at_utc: progress.last_advanced_at_utc, - }; - let closing_body = SingleFileMessagePackBackingStore::new(body_store).pull_all()?; - for expected in body_authority { - if closing_body - .iter() - .find(|row| row.r#type == expected.r#type && row.key == expected.key) - != Some(&expected) - { - bail!("Repository Body changed while authenticating workspace advancement"); - } - } - Ok(Some(authority)) -} - -fn progress_is_within_no_advance_lease( - last_advanced_at_utc: &str, - observed_at: chrono::DateTime, - no_advance_lease: chrono::Duration, -) -> Result { - let advanced = DateTime::parse_from_rfc3339(last_advanced_at_utc)?.with_timezone(&chrono::Utc); - let age = observed_at.signed_duration_since(advanced); - Ok(age >= chrono::Duration::zero() && age <= no_advance_lease) -} - -fn authenticate_against_launch( - entry: &WorkspaceCoverageProjectionProgressEntry, - launch: &WorkspaceCoverageManagedProcessLaunchEntry, - launch_digest: &str, -) -> Result<()> { - validate_shape(entry, true)?; - if entry.runtime_id != launch.runtime_id - || entry.launch_id != launch.launch_id - || entry.launch_envelope_digest != launch_digest - || entry.provider_incarnation_id != launch.provider_incarnation_id - || entry.provider_public_key != launch.provider_public_key - { - bail!("workspace coverage progress disagrees with exact managed launch"); - } - verify_signature(entry) -} - -fn validate_shape(entry: &WorkspaceCoverageProjectionProgressEntry, signed: bool) -> Result<()> { - if entry.schema_version != WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION { - bail!("workspace coverage progress schema is invalid"); - } - for (name, value) in [ - ("progress id", entry.progress_id.as_str()), - ("runtime id", &entry.runtime_id), - ("launch id", &entry.launch_id), - ("launch digest", &entry.launch_envelope_digest), - ("provider incarnation", &entry.provider_incarnation_id), - ("claim id", &entry.claim_id), - ("attempt id", &entry.attempt_id), - ("plan id", &entry.plan_id), - ("Body observation id", &entry.body_observation_id), - ( - "embedding artifact identity", - &entry.embedding_artifact_identity, - ), - ("unit kind", &entry.unit_kind), - ] { - require(name, value)?; - } - uuid::Uuid::parse_str(&entry.progress_id).context("progress id must be UUID")?; - uuid::Uuid::parse_str(&entry.launch_id).context("launch id must be UUID")?; - uuid::Uuid::parse_str(&entry.provider_incarnation_id) - .context("provider incarnation must be UUID")?; - if entry.claim_epoch == 0 - || entry.body_generation == 0 - || entry.embedding_dimensions == 0 - || entry.operation_timeout_ms == 0 - || entry.sequence == 0 - || entry.total_units == 0 - || entry.completed_units > entry.total_units - { - bail!("workspace coverage progress numeric bounds are invalid"); - } - if !matches!( - entry.phase.as_str(), - "preparing" | "projecting" | "verifying" | "committing" - ) || !matches!(entry.status.as_str(), "warming" | "failed" | "complete") - { - bail!("workspace coverage progress phase or status is invalid"); - } - if entry.status == "complete" - && (entry.phase != "committing" || entry.completed_units != entry.total_units) - { - bail!("completed workspace coverage progress lacks complete committed work"); - } - match (&entry.checkpoint_id, &entry.checkpoint_binding_sha256) { - (Some(id), Some(binding)) => { - require("progress checkpoint id", id)?; - if !binding.starts_with("sha256-") - || binding.len() != 71 - || !binding[7..] - .bytes() - .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase()) - { - bail!("workspace coverage progress checkpoint binding is not canonical SHA-256"); - } - } - (None, None) - if entry.sequence == 1 - && entry.phase == "preparing" - && entry.status == "warming" - && entry.completed_units == 0 => {} - _ => bail!("workspace coverage progress lacks exact durable checkpoint evidence"), - } - let operation = DateTime::parse_from_rfc3339(&entry.operation_started_at_utc)?; - let observed = DateTime::parse_from_rfc3339(&entry.observed_at_utc)?; - let advanced = DateTime::parse_from_rfc3339(&entry.last_advanced_at_utc)?; - if operation > observed || advanced > observed { - bail!("workspace coverage progress times are causally invalid"); - } - if entry.sequence == 1 - && (entry.phase != "preparing" - || entry.status != "warming" - || entry.completed_units != 0 - || entry.checkpoint_id.is_some() - || entry.checkpoint_binding_sha256.is_some() - || operation != observed - || advanced != observed) - { - bail!("workspace coverage progress genesis is not canonical"); - } - if entry.provider_public_key.len() != 32 - || entry.signature_algorithm != "ed25519" - || (signed && entry.provider_signature.len() != 64) - || (!signed && !entry.provider_signature.is_empty()) - { - bail!("workspace coverage progress signature material is invalid"); - } - Ok(()) -} - -fn validate_transition( - prior: &WorkspaceCoverageProjectionProgressEntry, - next: &WorkspaceCoverageProjectionProgressEntry, -) -> Result<()> { - validate_shape(prior, true)?; - validate_shape(next, true)?; - verify_signature(prior)?; - verify_signature(next)?; - authenticate_same_authority(prior, next)?; - if next.sequence - != prior - .sequence - .checked_add(1) - .ok_or_else(|| anyhow!("progress sequence exhausted"))? - { - bail!("workspace coverage progress sequence must advance exactly once"); - } - let prior_observed = DateTime::parse_from_rfc3339(&prior.observed_at_utc)?; - let next_observed = DateTime::parse_from_rfc3339(&next.observed_at_utc)?; - let prior_advanced = DateTime::parse_from_rfc3339(&prior.last_advanced_at_utc)?; - let next_advanced = DateTime::parse_from_rfc3339(&next.last_advanced_at_utc)?; - if next_observed <= prior_observed - || next.completed_units < prior.completed_units - || next_advanced < prior_advanced - || (next.completed_units > prior.completed_units) != (next_advanced > prior_advanced) - { - bail!("workspace coverage progress time or completion regressed"); - } - if next.completed_units > prior.completed_units - && (next.checkpoint_id == prior.checkpoint_id - || next.checkpoint_binding_sha256 == prior.checkpoint_binding_sha256) - { - bail!("workspace coverage advancement must name a new durable checkpoint"); - } - if next.completed_units == prior.completed_units { - if next.checkpoint_id != prior.checkpoint_id - || next.checkpoint_binding_sha256 != prior.checkpoint_binding_sha256 - { - bail!("workspace coverage checkpoint changed without durable advancement"); - } - if next.status == "warming" { - bail!("nonterminal workspace coverage progress must advance durable units"); - } - } - let prior_phase = phase_rank(&prior.phase)?; - let next_phase = phase_rank(&next.phase)?; - if next_phase < prior_phase || next_phase > prior_phase + 1 { - bail!("workspace coverage progress phase transition is invalid"); - } - match (prior.status.as_str(), next.status.as_str()) { - ("warming", "warming" | "failed" | "complete") => {} - ("failed" | "complete", _) => { - bail!("terminal workspace coverage progress cannot advance") - } - _ => bail!("workspace coverage progress status transition is invalid"), - } - Ok(()) -} - -fn existing_event_is_idempotent( - existing: &WorkspaceCoverageProjectionProgressEntry, - candidate: &WorkspaceCoverageProjectionProgressEntry, -) -> Result { - if existing == candidate { - return Ok(true); - } - bail!("workspace coverage progress identity collision") -} - -fn authenticate_same_authority( - a: &WorkspaceCoverageProjectionProgressEntry, - b: &WorkspaceCoverageProjectionProgressEntry, -) -> Result<()> { - if a.runtime_id != b.runtime_id - || a.launch_id != b.launch_id - || a.launch_envelope_digest != b.launch_envelope_digest - || a.provider_incarnation_id != b.provider_incarnation_id - || a.provider_public_key != b.provider_public_key - || a.claim_id != b.claim_id - || a.claim_epoch != b.claim_epoch - || a.attempt_id != b.attempt_id - || a.plan_id != b.plan_id - || a.body_observation_id != b.body_observation_id - || a.body_generation != b.body_generation - || a.embedding_artifact_identity != b.embedding_artifact_identity - || a.embedding_dimensions != b.embedding_dimensions - || a.operation_started_at_utc != b.operation_started_at_utc - || a.total_units != b.total_units - || a.unit_kind != b.unit_kind - { - bail!("workspace coverage progress authority or immutable plan identity changed"); - } - Ok(()) -} - -fn phase_rank(value: &str) -> Result { - Ok(match value { - "preparing" => 0, - "projecting" => 1, - "verifying" => 2, - "committing" => 3, - _ => bail!("invalid progress phase"), - }) -} -fn verify_signature(entry: &WorkspaceCoverageProjectionProgressEntry) -> Result<()> { - let key_bytes: [u8; 32] = entry - .provider_public_key - .as_slice() - .try_into() - .context("workspace coverage progress provider key length")?; - let sig_bytes: [u8; 64] = entry - .provider_signature - .as_slice() - .try_into() - .context("workspace coverage progress signature length")?; - VerifyingKey::from_bytes(&key_bytes)? - .verify( - &provider_message(&workspace_coverage_projection_progress_statement(entry)?), - &Signature::from_bytes(&sig_bytes), - ) - .context("workspace coverage progress signature is invalid") -} -fn require(name: &str, value: &str) -> Result<()> { - if value.trim().is_empty() { - bail!("workspace coverage {name} is empty") - } - Ok(()) -} -fn find_authority<'a>( - entries: &'a [CultCacheEnvelope], - ty: &str, - key: &str, -) -> Result<&'a CultCacheEnvelope> { - entries - .iter() - .find(|entry| entry.r#type == ty && entry.key == key) - .ok_or_else(|| anyhow!("workspace coverage progress authority {ty}/{key} is absent")) -} -fn find_current_claim<'a>( - coverage_opening: &'a [CultCacheEnvelope], - body_opening: &[CultCacheEnvelope], -) -> Result<&'a CultCacheEnvelope> { - let head: RepositoryBodyHead = - decode(find_authority(body_opening, BODY_HEAD_TYPE, BODY_HEAD_KEY)?)?; - find_authority( - coverage_opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&head.observation_id, head.generation), - ) -} -fn decode(entry: &CultCacheEnvelope) -> Result { - rmp_serde::from_slice(&entry.payload).context("decoding workspace coverage progress authority") -} -fn progress_key(id: &str) -> String { - format!("epiphany-local/workspace-coverage/projection-progress/event/{id}") -} -fn progress_envelope( - key: &str, - entry: &WorkspaceCoverageProjectionProgressEntry, -) -> Result { - Ok(CultCacheEnvelope { - r#type: WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE.into(), - key: key.into(), - payload: rmp_serde::to_vec(entry)?, - stored_at: chrono::Utc::now().to_rfc3339(), - schema_id: Some(WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE.into()), - }) -} -fn load_progress( - store: &OwnedRedbMessagePackBackingStore, - key: &str, -) -> Result> { - store - .pull_all()? - .iter() - .find(|env| env.r#type == WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE && env.key == key) - .map(decode) - .transpose() -} -fn latest_key(launch: &str, claim: &str) -> String { - format!("epiphany-local/workspace-coverage/projection-progress/latest/{launch}/{claim}") -} -fn provider_message(statement: &[u8]) -> Vec { - let mut out = Vec::with_capacity(PROGRESS_DOMAIN.len() + 8 + statement.len()); - out.extend_from_slice(PROGRESS_DOMAIN); - out.extend_from_slice(&(statement.len() as u64).to_be_bytes()); - out.extend_from_slice(statement); - out -} - -#[cfg(test)] -mod tests { - use super::*; - - fn entry(key: &SigningKey) -> WorkspaceCoverageProjectionProgressEntry { - let mut value = WorkspaceCoverageProjectionProgressEntry { - schema_version: WORKSPACE_COVERAGE_PROJECTION_PROGRESS_SCHEMA_VERSION.into(), - progress_id: uuid::Uuid::new_v4().to_string(), - runtime_id: "runtime".into(), - launch_id: uuid::Uuid::new_v4().to_string(), - launch_envelope_digest: "sha256-launch".into(), - provider_incarnation_id: uuid::Uuid::new_v4().to_string(), - provider_public_key: key.verifying_key().to_bytes().to_vec(), - claim_id: "claim".into(), - claim_epoch: 1, - attempt_id: "attempt".into(), - plan_id: "plan".into(), - body_observation_id: "body".into(), - body_generation: 1, - embedding_artifact_identity: "ollama:sha256-x".into(), - embedding_dimensions: 1024, - phase: "preparing".into(), - status: "warming".into(), - completed_units: 0, - total_units: 100, - unit_kind: "chunks".into(), - operation_started_at_utc: "2026-07-16T10:00:00Z".into(), - operation_timeout_ms: 120_000, - observed_at_utc: "2026-07-16T10:00:00Z".into(), - last_advanced_at_utc: "2026-07-16T10:00:00Z".into(), - sequence: 1, - checkpoint_id: None, - checkpoint_binding_sha256: None, - provider_signature: vec![], - signature_algorithm: "ed25519".into(), - }; - sign_workspace_coverage_projection_progress(&mut value, key).unwrap(); - value - } - fn advance( - prior: &WorkspaceCoverageProjectionProgressEntry, - key: &SigningKey, - ) -> WorkspaceCoverageProjectionProgressEntry { - let mut next = prior.clone(); - next.progress_id = uuid::Uuid::new_v4().to_string(); - next.sequence += 1; - next.completed_units += 1; - next.phase = "projecting".into(); - next.observed_at_utc = "2026-07-16T10:00:02Z".into(); - next.last_advanced_at_utc = next.observed_at_utc.clone(); - next.checkpoint_id = Some(format!("checkpoint-{}", next.sequence)); - next.checkpoint_binding_sha256 = Some(format!("sha256-{}", "b".repeat(64))); - sign_workspace_coverage_projection_progress(&mut next, key).unwrap(); - next - } - #[test] - fn valid_signed_transition_is_admitted() { - let k = SigningKey::from_bytes(&[7; 32]); - let a = entry(&k); - let b = advance(&a, &k); - validate_transition(&a, &b).unwrap(); - } - #[test] - fn replay_and_gap_are_refused() { - let k = SigningKey::from_bytes(&[7; 32]); - let a = entry(&k); - let mut b = advance(&a, &k); - b.sequence = 1; - assert!(validate_transition(&a, &b).is_err()); - b.sequence = 3; - assert!(validate_transition(&a, &b).is_err()); - } - #[test] - fn substitution_and_mutable_total_are_refused() { - let k = SigningKey::from_bytes(&[7; 32]); - let a = entry(&k); - for mutate in ["plan", "body", "model", "total", "operation"] { - let mut b = advance(&a, &k); - match mutate { - "plan" => b.plan_id.push('x'), - "body" => b.body_generation += 1, - "model" => b.embedding_artifact_identity.push('x'), - "total" => b.total_units += 1, - _ => b.operation_started_at_utc = "2026-07-16T10:00:01Z".into(), - }; - assert!(validate_transition(&a, &b).is_err(), "{mutate}"); - } - } - #[test] - fn checkpoint_progress_mapping_rejects_every_split_state() { - let k = SigningKey::from_bytes(&[7; 32]); - let genesis = entry(&k); - assert!( - checkpoint_progress_binding_alignment( - &genesis, - 1, - "checkpoint", - &format!("sha256-{}", "b".repeat(64)), - 1 - ) - .is_err() - ); - let current = advance(&genesis, &k); - let digest = current.checkpoint_binding_sha256.clone().unwrap(); - let id = current.checkpoint_id.clone().unwrap(); - checkpoint_progress_binding_alignment(¤t, 1, &id, &digest, 1).unwrap(); - assert!( - checkpoint_progress_binding_alignment(¤t, 2, "next-checkpoint", &digest, 2) - .is_err() - ); - let mut skipped = current.clone(); - skipped.sequence = 3; - assert!(checkpoint_progress_binding_alignment(&skipped, 1, &id, &digest, 1).is_err()); - assert!( - checkpoint_progress_binding_alignment(¤t, 1, "stale-head", &digest, 1).is_err() - ); - assert!( - checkpoint_progress_binding_alignment( - ¤t, - 1, - &id, - &format!("sha256-{}", "c".repeat(64)), - 1 - ) - .is_err() - ); - } - #[test] - fn provider_timeout_observation_is_not_progress_authority() { - let k = SigningKey::from_bytes(&[7; 32]); - let genesis = entry(&k); - let mut next = advance(&genesis, &k); - next.operation_timeout_ms += 1; - next.provider_signature.clear(); - sign_workspace_coverage_projection_progress(&mut next, &k).unwrap(); - validate_transition(&genesis, &next).unwrap(); - } - #[test] - fn completion_regression_and_phase_jump_are_refused() { - let k = SigningKey::from_bytes(&[7; 32]); - let a = entry(&k); - let mut b = advance(&a, &k); - b.completed_units = 0; - assert!(validate_transition(&a, &b).is_err()); - let mut b = advance(&a, &k); - b.phase = "verifying".into(); - assert!(validate_transition(&a, &b).is_err()); - } - #[test] - fn wrong_key_and_signature_substitution_are_refused() { - let k = SigningKey::from_bytes(&[7; 32]); - let wrong = SigningKey::from_bytes(&[8; 32]); - let mut a = entry(&k); - assert!(sign_workspace_coverage_projection_progress(&mut a, &wrong).is_err()); - a.plan_id.push('x'); - assert!(verify_signature(&a).is_err()); - } - #[test] - fn identity_collision_is_refused_but_exact_replay_is_idempotent() { - let k = SigningKey::from_bytes(&[7; 32]); - let a = entry(&k); - assert!(existing_event_is_idempotent(&a, &a).unwrap()); - let mut collision = a.clone(); - collision.completed_units += 1; - assert!(existing_event_is_idempotent(&a, &collision).is_err()); - } - #[test] - fn advancement_requires_new_durable_checkpoint() { - let k = SigningKey::from_bytes(&[7; 32]); - let a = entry(&k); - let mut b = advance(&a, &k); - b.checkpoint_id = a.checkpoint_id.clone(); - assert!(validate_transition(&a, &b).is_err()); - let mut initial = entry(&k); - assert!(validate_shape(&initial, true).is_ok()); - initial.completed_units = 1; - assert!(validate_shape(&initial, true).is_err()); - } - #[test] - fn genesis_is_exact_and_nonterminal_events_must_advance() { - let k = SigningKey::from_bytes(&[7; 32]); - let genesis = entry(&k); - for mutate in [ - "phase", - "status", - "count", - "checkpoint", - "observed", - "advanced", - ] { - let mut alien = genesis.clone(); - match mutate { - "phase" => alien.phase = "projecting".into(), - "status" => alien.status = "failed".into(), - "count" => alien.completed_units = 1, - "checkpoint" => { - alien.checkpoint_id = Some("checkpoint".into()); - alien.checkpoint_binding_sha256 = Some(format!("sha256-{}", "a".repeat(64))); - } - "observed" => alien.observed_at_utc = "2026-07-16T10:00:01Z".into(), - _ => alien.last_advanced_at_utc = "2026-07-16T10:00:01Z".into(), - } - assert!(validate_shape(&alien, true).is_err(), "{mutate}"); - } - let first = advance(&genesis, &k); - let mut no_advance = first.clone(); - no_advance.progress_id = uuid::Uuid::new_v4().to_string(); - no_advance.sequence += 1; - no_advance.observed_at_utc = "2026-07-16T10:00:03Z".into(); - no_advance.provider_signature.clear(); - sign_workspace_coverage_projection_progress(&mut no_advance, &k).unwrap(); - assert!(validate_transition(&first, &no_advance).is_err()); - } - #[test] - fn provider_cannot_author_stalled_and_terminal_statuses_do_not_advance() { - let k = SigningKey::from_bytes(&[7; 32]); - let genesis = entry(&k); - let mut stalled = genesis.clone(); - stalled.status = "stalled".into(); - assert!(validate_shape(&stalled, true).is_err()); - - let first = advance(&genesis, &k); - let mut failed = first.clone(); - failed.progress_id = uuid::Uuid::new_v4().to_string(); - failed.sequence += 1; - failed.status = "failed".into(); - failed.observed_at_utc = "2026-07-16T10:00:03Z".into(); - failed.provider_signature.clear(); - sign_workspace_coverage_projection_progress(&mut failed, &k).unwrap(); - validate_transition(&first, &failed).unwrap(); - let mut replay = failed.clone(); - replay.progress_id = uuid::Uuid::new_v4().to_string(); - replay.sequence += 1; - replay.observed_at_utc = "2026-07-16T10:00:04Z".into(); - replay.provider_signature.clear(); - sign_workspace_coverage_projection_progress(&mut replay, &k).unwrap(); - assert!(validate_transition(&failed, &replay).is_err()); - } - #[test] - fn transition_reauthenticates_both_signed_events() { - let k = SigningKey::from_bytes(&[7; 32]); - let mut prior = entry(&k); - let next = advance(&prior, &k); - prior.plan_id.push('x'); - assert!(validate_transition(&prior, &next).is_err()); - let prior = entry(&k); - let mut next = advance(&prior, &k); - next.provider_signature[0] ^= 1; - assert!(validate_transition(&prior, &next).is_err()); - } - - #[test] - fn no_advance_lease_uses_durable_advancement_time_only() { - let now = chrono::DateTime::parse_from_rfc3339("2026-07-16T10:05:00Z") - .unwrap() - .with_timezone(&chrono::Utc); - let lease = chrono::Duration::seconds(300); - assert!(progress_is_within_no_advance_lease("2026-07-16T10:00:00Z", now, lease).unwrap()); - assert!(!progress_is_within_no_advance_lease("2026-07-16T09:59:59Z", now, lease).unwrap()); - assert!(!progress_is_within_no_advance_lease("2026-07-16T10:05:01Z", now, lease).unwrap()); - } -} diff --git a/epiphany-core/src/workspace_coverage_projector.rs b/epiphany-core/src/workspace_coverage_projector.rs deleted file mode 100644 index 46df21bf..00000000 --- a/epiphany-core/src/workspace_coverage_projector.rs +++ /dev/null @@ -1,5267 +0,0 @@ -use crate::repository_body_observer::RepositoryBodyReadSession; -use crate::semantic_backend::{ - CollectionCompatibility, OllamaEmbedder, QDRANT_POINT_BATCH_MAX, QdrantBackend, SemanticPoint, - SemanticStoredPoint, -}; -use crate::workspace_coverage_process_documents::{ - publish_workspace_coverage_advancement_sight, publish_workspace_coverage_terminal_sight, -}; -use crate::workspace_coverage_projection_batch_checkpoint::{ - ObservedWorkspaceCoverageBatchInput, WORKSPACE_COVERAGE_BATCH_CHECKPOINT_MAX_POINTS, - WorkspaceCoverageProjectionBatchCheckpointAdmission, - WorkspaceCoverageProjectionBatchCheckpointEntry, - WorkspaceCoverageProjectionBatchCheckpointHeadEntry, admit_observed_workspace_coverage_batch, - load_authenticated_checkpoint_chain, -}; -use crate::workspace_coverage_projection_progress::{ - authenticate_workspace_coverage_projection_progress, - load_latest_workspace_coverage_projection_progress, - publish_workspace_coverage_progress_genesis, -}; -use crate::{ - BODY_BINDING_KEY, BODY_BINDING_TYPE, BODY_HEAD_KEY, BODY_HEAD_TYPE, BODY_MANIFEST_TYPE, - BODY_OBSERVATION_TYPE, HostIncarnationIdentityEntry, RepositoryBodyHead, - RepositoryBodyObservationBasis, WORKSPACE_COVERAGE_HEAD_SCHEMA_VERSION, - WORKSPACE_COVERAGE_RECEIPT_SCHEMA_VERSION, WorkspaceCoverageChunkDescriptor, - WorkspaceCoverageHead, WorkspaceCoverageObligation, WorkspaceCoveragePointBinding, - WorkspaceCoveragePointPayload, WorkspaceCoveragePolicy, WorkspaceCoverageProjectionPlan, - WorkspaceCoverageReceipt, WorkspaceCoverageVectorBinding, - derive_workspace_coverage_obligation_from_authenticated_manifest, - derive_workspace_coverage_projection_plan, load_latest_workspace_coverage_provider_heartbeat, - observe_runtime_repository_body_basis, refine_workspace_coverage_obligation_utf8, - runtime_repository_body_store_binding, validate_workspace_coverage_head, - validate_workspace_coverage_projection_plan, workspace_coverage_execution_collection, - workspace_coverage_process_documents::{ - authenticate_historical_workspace_coverage_managed_process_launch_with_envelope_digest, - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest, - authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest, - authenticate_workspace_coverage_replacement_lineage, - authenticate_workspace_coverage_termination_with_envelope_digest, - }, -}; -use anyhow::{Context, Result, anyhow, bail}; -use cultcache_rs::{ - CacheBackingStore, CultCacheEnvelope, DatabaseEntry, OwnedRedbMessagePackBackingStore, - SingleFileMessagePackBackingStore, -}; -use ed25519_dalek::SigningKey; -use serde::Serialize; -use sha2::{Digest, Sha256}; -use std::path::{Path, PathBuf}; - -pub(crate) const CLAIM_TYPE: &str = "gamecult.epiphany.workspace_coverage_projection_claim"; -pub(crate) const ATTEMPT_TYPE: &str = "gamecult.epiphany.workspace_coverage_projection_attempt"; -/// One authenticated Qdrant batch is one durable checkpoint. The shared bound -/// keeps transport, readback, and immutable checkpoint cardinality identical. -const WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS: usize = - WORKSPACE_COVERAGE_BATCH_CHECKPOINT_MAX_POINTS; -const _: () = assert!(WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS <= QDRANT_POINT_BATCH_MAX); -const CLAIM_SCHEMA: &str = "gamecult.epiphany.workspace_coverage_projection_claim.v1"; -const ATTEMPT_SCHEMA: &str = "gamecult.epiphany.workspace_coverage_projection_attempt.v1"; -const CLAIM_SCHEMA_V2: &str = "gamecult.epiphany.workspace_coverage_projection_claim.v2"; -const ATTEMPT_SCHEMA_V2: &str = "gamecult.epiphany.workspace_coverage_projection_attempt.v2"; -const CLAIM_SCHEMA_V3: &str = "gamecult.epiphany.workspace_coverage_projection_claim.v3"; -const ATTEMPT_SCHEMA_V3: &str = "gamecult.epiphany.workspace_coverage_projection_attempt.v3"; -const RECOVERY_TYPE: &str = "gamecult.epiphany.workspace_coverage_recovery_receipt"; -const RECOVERY_SCHEMA: &str = "gamecult.epiphany.workspace_coverage_recovery_receipt.v0"; -pub(crate) const PROJECTION_SCHEMA: &str = "gamecult.epiphany.workspace_bytes_projection.v0"; -pub(crate) const CHUNKER_ID: &str = "utf8_lines_96_overlap_8_max_12288_bytes_v1"; -pub const WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES: u64 = 4 * 1024 * 1024; -const CHUNK_LINES: usize = 96; -const CHUNK_OVERLAP_LINES: usize = 8; -const CHUNK_MAX_BYTES: usize = 12 * 1024; -const RECEIPT_TYPE: &str = "gamecult.epiphany.workspace_coverage_receipt"; -const HEAD_TYPE: &str = "gamecult.epiphany.workspace_coverage_head"; -const HEAD_KEY: &str = "current"; -const RETENTION_HEAD_TYPE: &str = "gamecult.epiphany.workspace_coverage_retention_head"; -const RETENTION_HEAD_KEY: &str = "current"; -const RETENTION_HEAD_SCHEMA: &str = "gamecult.epiphany.workspace_coverage_retention_head.v0"; -pub(crate) const COLLECTION_RETIREMENT_EVIDENCE_TYPE: &str = - "gamecult.epiphany.workspace_coverage_collection_retirement_evidence"; -const COLLECTION_RETIREMENT_EVIDENCE_SCHEMA: &str = - "gamecult.epiphany.workspace_coverage_collection_retirement_evidence.v0"; -pub(crate) const OBLIGATION_TYPE: &str = "gamecult.epiphany.workspace_coverage_obligation"; -pub(crate) const PLAN_TYPE: &str = "gamecult.epiphany.workspace_coverage_projection_plan"; - -#[cfg(test)] -#[derive(Clone, Debug)] -struct WorkspaceCoverageProjectionInput { - pub point_id: String, - pub text: String, - pub vector: Vec, -} - -pub(crate) struct WorkspaceCoverageProjectionExecutionAuthority<'a> { - pub coverage_authority: &'a crate::WorkspaceCoverageAuthority, - pub runtime_store: &'a Path, - pub local_verse_store: &'a Path, - pub runtime_id: &'a str, - pub trusted_host: &'a HostIncarnationIdentityEntry, - pub provider_signing_key: &'a SigningKey, - pub operation_timeout_ms: u64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct WorkspaceCoverageObservedBinding { - collection_name: String, - point_count: u64, - point_set_sha256: String, - point_binding_set_sha256: String, - vector_binding_set_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageRecoveryOutcome { - pub claim_id: String, - pub claim_epoch: u64, - pub managed_process_launch_id: String, - pub executor_incarnation: String, - pub recovery_receipt_id: String, - pub recovery_receipt_digest: String, -} - -pub(crate) trait WorkspaceCoverageProjectionPort { - fn ensure_exact_collection( - &mut self, - collection: &str, - compatibility: &CollectionCompatibility, - ) -> Result<()>; - fn upsert_waited_batch( - &mut self, - collection: &str, - points: &[SemanticPoint], - ) -> Result<()>; - fn observe_exact_ids( - &mut self, - collection: &str, - point_ids: &[String], - ) -> Result>>; - fn observe_all( - &mut self, - collection: &str, - ) -> Result>>; -} - -/// Read-only Qdrant surface used by Mind's bounded repository-readiness join. -/// It can observe one exact collection, but cannot create, mutate, or retire it. -#[allow(dead_code)] // Sealed read surface for the Mind readiness join. -pub(crate) trait WorkspaceCoverageEvidencePort { - fn authenticate_exact_collection( - &mut self, - collection: &str, - compatibility: &CollectionCompatibility, - ) -> Result<()>; - - fn observe_all_for_evidence( - &mut self, - collection: &str, - ) -> Result>>; -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct WorkspaceCoverageRetirementCandidate { - pub collection_name: String, - pub compatibility: CollectionCompatibility, - pub claim_id: String, - pub attempt_id: String, - pub plan_id: String, - pub body_observation_id: String, - pub body_generation: u64, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_collection_retirement_evidence", - schema = "WorkspaceCoverageCollectionRetirementEvidence" -)] -pub(crate) struct WorkspaceCoverageCollectionRetirementEvidence { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub collection_name: String, - #[cultcache(key = 2)] - pub collection_compatibility_sha256: String, - #[cultcache(key = 3)] - pub claim_id: String, - #[cultcache(key = 4)] - pub attempt_id: String, - #[cultcache(key = 5)] - pub plan_id: String, - #[cultcache(key = 6)] - pub body_observation_id: String, - #[cultcache(key = 7)] - pub body_generation: u64, - #[cultcache(key = 8)] - pub runtime_id: String, - #[cultcache(key = 9)] - pub workspace_id: String, - #[cultcache(key = 10)] - pub coverage_binding_id: String, - #[cultcache(key = 11)] - pub coverage_binding_envelope_sha256: String, - #[cultcache(key = 12)] - pub coverage_store_file_identity: String, - #[cultcache(key = 13)] - pub observed_result: String, - #[cultcache(key = 14)] - pub observed_at_utc: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_retention_head", - schema = "WorkspaceCoverageRetentionHead" -)] -pub(crate) struct WorkspaceCoverageRetentionHead { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub sequence: u64, - #[cultcache(key = 2)] - pub prior_head_envelope_sha256: Option, - #[cultcache(key = 3)] - pub runtime_id: String, - #[cultcache(key = 4)] - pub workspace_id: String, - #[cultcache(key = 5)] - pub coverage_binding_id: String, - #[cultcache(key = 6)] - pub coverage_binding_envelope_sha256: String, - #[cultcache(key = 7)] - pub coverage_store_file_identity: String, - #[cultcache(key = 8)] - pub retired_envelope_count: u64, - #[cultcache(key = 9)] - pub retired_identity_digest_root: String, - #[cultcache(key = 10)] - pub family_counts: Vec, - #[cultcache(key = 11)] - pub family_digest_roots: Vec, - #[cultcache(key = 12)] - pub compacted_body_evidence_root: String, - #[cultcache(key = 13)] - pub compacted_plan_evidence_root: String, - #[cultcache(key = 14)] - pub compacted_claim_evidence_root: String, - #[cultcache(key = 15)] - pub compacted_receipt_evidence_root: String, - #[cultcache(key = 16)] - pub compacted_collection_retirement_evidence_root: String, - #[cultcache(key = 17)] - pub compacted_through_body_generation: u64, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum WorkspaceCoverageRetentionResult { - Noop, - Compacted, - HistoricalBodyMovement, -} - -fn is_sha256_digest(value: &str) -> bool { - let hex = value.strip_prefix("sha256-").unwrap_or(value); - hex.len() == 64 && hex.bytes().all(|byte| byte.is_ascii_hexdigit()) -} - -fn fold_digest(domain: &str, prior: &str, values: impl IntoIterator) -> String { - let mut values = values.into_iter().collect::>(); - values.sort(); - let mut hasher = Sha256::new(); - hasher.update(domain.as_bytes()); - hasher.update([0]); - hasher.update(prior.as_bytes()); - for value in values { - hasher.update([0]); - hasher.update(value.as_bytes()); - } - format!("sha256-{:x}", hasher.finalize()) -} - -fn validate_collection_retirement_evidence( - evidence: &WorkspaceCoverageCollectionRetirementEvidence, -) -> Result<()> { - if evidence.schema_version != COLLECTION_RETIREMENT_EVIDENCE_SCHEMA - || evidence.observed_result != "retired-or-absent" - || evidence.collection_name.trim().is_empty() - || evidence.claim_id.trim().is_empty() - || evidence.attempt_id.trim().is_empty() - || evidence.plan_id.trim().is_empty() - || evidence.body_observation_id.trim().is_empty() - || evidence.runtime_id.trim().is_empty() - || evidence.workspace_id.trim().is_empty() - || evidence.coverage_binding_id.trim().is_empty() - || evidence.coverage_store_file_identity.trim().is_empty() - || !is_sha256_digest(&evidence.collection_compatibility_sha256) - || !is_sha256_digest(&evidence.coverage_binding_envelope_sha256) - { - bail!("invalid workspace coverage collection-retirement evidence"); - } - chrono::DateTime::parse_from_rfc3339(&evidence.observed_at_utc)?; - Ok(()) -} - -fn parse_retention_family_values( - values: &[String], - kind: &str, -) -> Result> { - let mut parsed = std::collections::BTreeMap::new(); - for encoded in values { - let (ty, value) = encoded - .rsplit_once('=') - .ok_or_else(|| anyhow!("invalid retention family {kind}"))?; - if ty.trim().is_empty() - || value.trim().is_empty() - || parsed.insert(ty.into(), value.into()).is_some() - { - bail!("duplicate or empty retention family {kind}"); - } - } - Ok(parsed) -} - -fn validate_retention_head( - head: &WorkspaceCoverageRetentionHead, - authority: &crate::WorkspaceCoverageAuthority, -) -> Result<()> { - let counts = parse_retention_family_values(&head.family_counts, "count")?; - let roots = parse_retention_family_values(&head.family_digest_roots, "root")?; - let count_keys = counts.keys().collect::>(); - let root_keys = roots.keys().collect::>(); - let mut count_total = 0u64; - for count in counts.values() { - count_total = count_total - .checked_add(count.parse::()?) - .ok_or_else(|| anyhow!("retention family count overflow"))?; - } - if head.schema_version != RETENTION_HEAD_SCHEMA - || head.sequence == 0 - || (head.sequence == 1) != head.prior_head_envelope_sha256.is_none() - || head - .prior_head_envelope_sha256 - .as_deref() - .is_some_and(|digest| !is_sha256_digest(digest)) - || head.runtime_id != authority.store_binding.runtime_id - || head.workspace_id != authority.store_binding.workspace_id - || head.coverage_binding_id != authority.store_binding.binding_id - || head.coverage_binding_envelope_sha256 != authority.store_binding_envelope_sha256 - || head.coverage_store_file_identity != authority.store.file_identity() - || head.retired_envelope_count == 0 - || count_total != head.retired_envelope_count - || count_keys != root_keys - || roots.values().any(|root| !is_sha256_digest(root)) - || !is_sha256_digest(&head.retired_identity_digest_root) - || !is_sha256_digest(&head.compacted_body_evidence_root) - || !is_sha256_digest(&head.compacted_plan_evidence_root) - || !is_sha256_digest(&head.compacted_claim_evidence_root) - || !is_sha256_digest(&head.compacted_receipt_evidence_root) - || !is_sha256_digest(&head.compacted_collection_retirement_evidence_root) - { - bail!("invalid or forked workspace coverage retention accumulator"); - } - Ok(()) -} - -fn retention_allowed_type(ty: &str) -> bool { - matches!( - ty, - "gamecult.epiphany.workspace_coverage_store_binding" - | OBLIGATION_TYPE - | PLAN_TYPE - | CLAIM_TYPE - | ATTEMPT_TYPE - | RECEIPT_TYPE - | HEAD_TYPE - | RECOVERY_TYPE - | COLLECTION_RETIREMENT_EVIDENCE_TYPE - | RETENTION_HEAD_TYPE - | crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE - | crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_HEAD_TYPE - | crate::workspace_coverage_projection_progress::WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE - ) -} - -fn validate_retention_opening_rows( - opening: &[CultCacheEnvelope], - authority: &crate::WorkspaceCoverageAuthority, -) -> Result<()> { - for entry in opening { - match entry.r#type.as_str() { - "gamecult.epiphany.workspace_coverage_store_binding" => { - let _: crate::WorkspaceCoverageStoreBinding = decode(entry)?; - } - OBLIGATION_TYPE => { - let value: WorkspaceCoverageObligation = decode(entry)?; - if value.obligation_id.trim().is_empty() || value.body_generation == 0 { - bail!("invalid retained workspace coverage obligation"); - } - } - PLAN_TYPE => { - let value: WorkspaceCoverageProjectionPlan = decode(entry)?; - if value.plan_id.trim().is_empty() || value.obligation_id.trim().is_empty() { - bail!("invalid retained workspace coverage plan"); - } - } - CLAIM_TYPE => validate_projection_claim(&decode(entry)?)?, - ATTEMPT_TYPE => validate_projection_attempt(&decode(entry)?)?, - RECEIPT_TYPE => { - let value: WorkspaceCoverageReceipt = decode(entry)?; - if value.receipt_id.trim().is_empty() || value.claim_id.trim().is_empty() { - bail!("invalid retained workspace coverage receipt"); - } - } - HEAD_TYPE => { - let _: WorkspaceCoverageHead = decode(entry)?; - } - RECOVERY_TYPE => validate_recovery_receipt(&decode(entry)?)?, - COLLECTION_RETIREMENT_EVIDENCE_TYPE => { - validate_collection_retirement_evidence(&decode(entry)?)? - } - RETENTION_HEAD_TYPE => validate_retention_head(&decode(entry)?, authority)?, - crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE => { - let _: WorkspaceCoverageProjectionBatchCheckpointEntry = decode(entry)?; - } - crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_HEAD_TYPE => { - let _: WorkspaceCoverageProjectionBatchCheckpointHeadEntry = decode(entry)?; - } - crate::workspace_coverage_projection_progress::WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE => { - let _: crate::workspace_coverage_projection_progress::WorkspaceCoverageProjectionProgressEntry = decode(entry)?; - } - _ => bail!("workspace coverage retention refuses unknown type {}", entry.r#type), - } - } - Ok(()) -} - -/// Compacts only generations made unreachable by a newer terminal head. The -/// singleton accumulator is historical evidence and is never consulted by -/// current/readiness/recovery paths. -pub(crate) fn compact_workspace_coverage_history( - runtime_store: &Path, - authority: &crate::WorkspaceCoverageAuthority, -) -> Result { - let body_before = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let opening = authority.store.pull_all()?; - if let Some(unknown) = opening - .iter() - .find(|entry| !retention_allowed_type(&entry.r#type)) - { - bail!( - "workspace coverage retention refuses unknown type {}", - unknown.r#type - ); - } - validate_retention_opening_rows(&opening, authority)?; - let Some(current_head_env) = find(&opening, HEAD_TYPE, HEAD_KEY) else { - return Ok(WorkspaceCoverageRetentionResult::Noop); - }; - let current_head: WorkspaceCoverageHead = decode(current_head_env)?; - if current_head.body_generation != body_before.generation - || current_head.body_observation_id != body_before.observation_id - { - return Ok(WorkspaceCoverageRetentionResult::HistoricalBodyMovement); - } - let preserve_from = current_head.body_generation.saturating_sub(1); - let claims = opening - .iter() - .filter(|entry| entry.r#type == CLAIM_TYPE) - .map(|entry| Ok((entry, decode::(entry)?))) - .collect::>>()?; - let active_generations = claims - .iter() - .filter(|(_, claim)| claim.status == "running") - .map(|(_, claim)| claim.body_generation) - .collect::>(); - let eligible_claims = claims - .iter() - .filter(|(_, claim)| { - claim.body_generation < preserve_from - && claim.status != "running" - && !active_generations.contains(&claim.body_generation) - }) - .map(|(_, claim)| claim.claim_id.clone()) - .collect::>(); - if eligible_claims.is_empty() { - return Ok(WorkspaceCoverageRetentionResult::Noop); - } - let eligible_generations = claims - .iter() - .filter(|(_, claim)| eligible_claims.contains(&claim.claim_id)) - .map(|(_, claim)| claim.body_generation) - .collect::>(); - let eligible_obligations = opening - .iter() - .filter(|entry| entry.r#type == OBLIGATION_TYPE) - .filter_map(|entry| { - decode::(entry) - .ok() - .map(|value| (entry, value)) - }) - .filter(|(_, value)| eligible_generations.contains(&value.body_generation)) - .map(|(entry, value)| (entry.clone(), value.obligation_id)) - .collect::>(); - let obligation_ids = eligible_obligations - .iter() - .map(|(_, id)| id.clone()) - .collect::>(); - let eligible_plans = opening - .iter() - .filter(|entry| entry.r#type == PLAN_TYPE) - .filter_map(|entry| { - decode::(entry) - .ok() - .map(|value| (entry, value)) - }) - .filter(|(_, value)| obligation_ids.contains(&value.obligation_id)) - .map(|(entry, value)| (entry.clone(), value.plan_id)) - .collect::>(); - let mut deletions = opening - .iter() - .filter(|entry| match entry.r#type.as_str() { - CLAIM_TYPE => decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - ATTEMPT_TYPE => decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - RECEIPT_TYPE => decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - RECOVERY_TYPE => decode::(entry).is_ok_and(|value| { - eligible_claims.contains(&value.old_claim_id) - && eligible_claims.contains(&value.new_claim_id) - }), - COLLECTION_RETIREMENT_EVIDENCE_TYPE => - decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_TYPE => - decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - crate::workspace_coverage_projection_batch_checkpoint::WORKSPACE_COVERAGE_PROJECTION_BATCH_CHECKPOINT_HEAD_TYPE => - decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - crate::workspace_coverage_projection_progress::WORKSPACE_COVERAGE_PROJECTION_PROGRESS_TYPE => - decode::(entry) - .is_ok_and(|value| eligible_claims.contains(&value.claim_id)), - _ => false, - }) - .cloned() - .collect::>(); - deletions.extend(eligible_obligations.iter().map(|(entry, _)| entry.clone())); - deletions.extend(eligible_plans.iter().map(|(entry, _)| entry.clone())); - for claim_id in &eligible_claims { - let attempts = opening - .iter() - .filter(|entry| entry.r#type == ATTEMPT_TYPE) - .map(decode::) - .collect::>>()? - .into_iter() - .filter(|attempt| &attempt.claim_id == claim_id); - for attempt in attempts { - let plan: WorkspaceCoverageProjectionPlan = decode( - find(&opening, PLAN_TYPE, &attempt.plan_id) - .ok_or_else(|| anyhow!("retired attempt lost its exact plan"))?, - )?; - let obligation: WorkspaceCoverageObligation = decode( - find(&opening, OBLIGATION_TYPE, &plan.obligation_id) - .ok_or_else(|| anyhow!("retired plan lost its exact obligation"))?, - )?; - let expected_collection = workspace_coverage_execution_collection( - &plan.plan_id, - claim_id, - attempt.claim_epoch, - )?; - let expected_compatibility = format!( - "sha256-{:x}", - Sha256::digest(rmp_serde::to_vec_named(&collection_compatibility(&plan))?) - ); - let evidence = opening - .iter() - .filter(|entry| entry.r#type == COLLECTION_RETIREMENT_EVIDENCE_TYPE) - .map(|entry| decode::(entry)) - .collect::>>()? - .into_iter() - .find(|value| { - value.claim_id == *claim_id && value.attempt_id == attempt.attempt_id - }); - let Some(evidence) = evidence else { - return Ok(WorkspaceCoverageRetentionResult::Noop); - }; - validate_collection_retirement_evidence(&evidence)?; - if evidence.collection_name != expected_collection - || evidence.collection_compatibility_sha256 != expected_compatibility - || evidence.plan_id != plan.plan_id - || evidence.body_observation_id != obligation.body_observation_id - || evidence.body_generation != obligation.body_generation - || evidence.runtime_id != authority.store_binding.runtime_id - || evidence.workspace_id != authority.store_binding.workspace_id - || evidence.coverage_binding_id != authority.store_binding.binding_id - || evidence.coverage_binding_envelope_sha256 - != authority.store_binding_envelope_sha256 - || evidence.coverage_store_file_identity != authority.store.file_identity() - { - bail!( - "workspace coverage retirement evidence disagrees with exact retired authority" - ); - } - } - } - deletions.sort_by(|left, right| (&left.r#type, &left.key).cmp(&(&right.r#type, &right.key))); - deletions.dedup_by(|left, right| left.r#type == right.r#type && left.key == right.key); - if deletions.is_empty() { - return Ok(WorkspaceCoverageRetentionResult::Noop); - } - let prior_env = find(&opening, RETENTION_HEAD_TYPE, RETENTION_HEAD_KEY).cloned(); - let prior = prior_env - .as_ref() - .map(decode::) - .transpose()?; - if let Some(prior) = &prior { - validate_retention_head(prior, authority)?; - if prior.compacted_through_body_generation > current_head.body_generation { - bail!("retention accumulator frontier exceeds current terminal Body generation"); - } - } - let retired_frontier = *eligible_generations.iter().max().unwrap_or(&0); - if retired_frontier > current_head.body_generation - || prior - .as_ref() - .is_some_and(|value| retired_frontier < value.compacted_through_body_generation) - { - bail!("retention compaction frontier is non-monotonic or exceeds current terminal"); - } - let envelope_digests = deletions - .iter() - .map(|entry| { - format!( - "{}:{}:{}", - entry.r#type, - entry.key, - cultcache_envelope_digest(entry) - ) - }) - .collect::>(); - let family = |ty: &str| { - deletions - .iter() - .filter(|entry| entry.r#type == ty) - .map(cultcache_envelope_digest) - .collect::>() - }; - let mut families = std::collections::BTreeMap::>::new(); - for entry in &deletions { - families - .entry(entry.r#type.clone()) - .or_default() - .push(cultcache_envelope_digest(entry)); - } - let mut family_counts = std::collections::BTreeMap::::new(); - let mut family_roots = std::collections::BTreeMap::::new(); - if let Some(prior) = &prior { - for encoded in &prior.family_counts { - let (ty, count) = encoded - .rsplit_once('=') - .ok_or_else(|| anyhow!("invalid retention family count"))?; - family_counts.insert(ty.into(), count.parse()?); - } - for encoded in &prior.family_digest_roots { - let (ty, root) = encoded - .rsplit_once('=') - .ok_or_else(|| anyhow!("invalid retention family root"))?; - family_roots.insert(ty.into(), root.into()); - } - } - for (ty, values) in &families { - *family_counts.entry(ty.clone()).or_default() += values.len() as u64; - let prior_family_root = family_roots.get(ty).map_or("", String::as_str); - family_roots.insert( - ty.clone(), - fold_digest( - "workspace-coverage-retention-family-v0", - prior_family_root, - values.clone(), - ), - ); - } - let prior_root = prior - .as_ref() - .map_or("", |value| value.retired_identity_digest_root.as_str()); - let head = WorkspaceCoverageRetentionHead { - schema_version: RETENTION_HEAD_SCHEMA.into(), - sequence: prior.as_ref().map_or(Ok(1), |value| { - value - .sequence - .checked_add(1) - .ok_or_else(|| anyhow!("retention sequence overflow")) - })?, - prior_head_envelope_sha256: prior_env.as_ref().map(cultcache_envelope_digest), - runtime_id: authority.store_binding.runtime_id.clone(), - workspace_id: authority.store_binding.workspace_id.clone(), - coverage_binding_id: authority.store_binding.binding_id.clone(), - coverage_binding_envelope_sha256: authority.store_binding_envelope_sha256.clone(), - coverage_store_file_identity: authority.store.file_identity().into(), - retired_envelope_count: prior - .as_ref() - .map_or(0, |value| value.retired_envelope_count) - .checked_add(u64::try_from(deletions.len())?) - .ok_or_else(|| anyhow!("retention envelope count overflow"))?, - retired_identity_digest_root: fold_digest( - "workspace-coverage-retention-identities-v0", - prior_root, - envelope_digests, - ), - family_counts: family_counts - .into_iter() - .map(|(ty, count)| format!("{ty}={count}")) - .collect(), - family_digest_roots: family_roots - .into_iter() - .map(|(ty, root)| format!("{ty}={root}")) - .collect(), - compacted_body_evidence_root: fold_digest( - "workspace-coverage-retention-body-v0", - prior - .as_ref() - .map_or("", |v| v.compacted_body_evidence_root.as_str()), - family(OBLIGATION_TYPE), - ), - compacted_plan_evidence_root: fold_digest( - "workspace-coverage-retention-plan-v0", - prior - .as_ref() - .map_or("", |v| v.compacted_plan_evidence_root.as_str()), - family(PLAN_TYPE), - ), - compacted_claim_evidence_root: fold_digest( - "workspace-coverage-retention-claim-v0", - prior - .as_ref() - .map_or("", |v| v.compacted_claim_evidence_root.as_str()), - family(CLAIM_TYPE), - ), - compacted_receipt_evidence_root: fold_digest( - "workspace-coverage-retention-receipt-v0", - prior - .as_ref() - .map_or("", |v| v.compacted_receipt_evidence_root.as_str()), - family(RECEIPT_TYPE), - ), - compacted_collection_retirement_evidence_root: fold_digest( - "workspace-coverage-retention-collection-retirement-v0", - prior.as_ref().map_or("", |v| { - v.compacted_collection_retirement_evidence_root.as_str() - }), - family(COLLECTION_RETIREMENT_EVIDENCE_TYPE), - ), - compacted_through_body_generation: retired_frontier, - }; - let replacement = envelope(RETENTION_HEAD_TYPE, RETENTION_HEAD_KEY, &head)?; - if !authority.store.replace_and_delete_if_snapshot_unchanged( - &opening, - vec![replacement], - &deletions, - )? { - bail!("workspace coverage retention lost exact snapshot compare-and-swap"); - } - let body_after = crate::load_current_runtime_repository_body_basis(runtime_store)?; - if body_after != body_before { - return Ok(WorkspaceCoverageRetentionResult::HistoricalBodyMovement); - } - Ok(WorkspaceCoverageRetentionResult::Compacted) -} - -pub(crate) trait WorkspaceCoverageRetirementPort { - fn retire_exact( - &mut self, - collection: &str, - compatibility: &CollectionCompatibility, - ) -> Result<()>; -} - -impl WorkspaceCoverageRetirementPort for QdrantBackend { - fn retire_exact( - &mut self, - collection: &str, - compatibility: &CollectionCompatibility, - ) -> Result<()> { - self.retire_exact_collection(collection, compatibility) - } -} - -impl WorkspaceCoverageProjectionPort for QdrantBackend { - fn ensure_exact_collection( - &mut self, - name: &str, - expected: &CollectionCompatibility, - ) -> Result<()> { - QdrantBackend::ensure_exact_collection(self, name, expected) - } - fn upsert_waited_batch( - &mut self, - name: &str, - points: &[SemanticPoint], - ) -> Result<()> { - self.upsert_point_batch_waited(name, points).map(|_| ()) - } - fn observe_exact_ids( - &mut self, - name: &str, - point_ids: &[String], - ) -> Result>> { - self.retrieve_points_by_ids(name, point_ids) - } - fn observe_all( - &mut self, - name: &str, - ) -> Result>> { - self.points_for_scope(name, &[]) - } -} - -impl WorkspaceCoverageEvidencePort for QdrantBackend { - fn authenticate_exact_collection( - &mut self, - name: &str, - expected: &CollectionCompatibility, - ) -> Result<()> { - if !self.collection_exists(name)? || self.collection_compatibility(name)? != *expected { - bail!("live workspace coverage collection is absent or incompatible"); - } - Ok(()) - } - - fn observe_all_for_evidence( - &mut self, - name: &str, - ) -> Result>> { - self.points_for_scope(name, &[]) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -#[allow(dead_code)] // Sealed evidence for the Mind readiness join. -pub(crate) struct WorkspaceCoverageReadinessEvidence { - pub workspace_id: String, - pub body_binding_sha256: String, - pub manifest_root_sha256: String, - pub policy_id: String, - pub policy_sha256: String, - pub obligation_id: String, - pub obligation_envelope_digest: String, - pub plan_id: String, - pub plan_envelope_digest: String, - pub claim_id: String, - pub claim_epoch: u64, - pub claim_envelope_digest: String, - pub attempt_id: String, - pub attempt_envelope_digest: String, - pub receipt_id: String, - pub receipt_envelope_digest: String, - pub head_envelope_digest: String, - pub collection_name: String, - pub observed_point_count: u64, - pub observed_point_set_sha256: String, - pub observed_point_binding_set_sha256: String, - pub observed_vector_binding_set_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_projection_claim", - schema = "WorkspaceCoverageProjectionClaim" -)] -pub(crate) struct WorkspaceCoverageProjectionClaim { - #[cultcache(key = 0)] - pub(crate) schema_version: String, - #[cultcache(key = 1)] - pub(crate) claim_id: String, - #[cultcache(key = 2)] - pub(crate) claim_epoch: u64, - #[cultcache(key = 3)] - pub(crate) plan_id: String, - #[cultcache(key = 4)] - pub(crate) attempt_id: String, - #[cultcache(key = 5)] - pub(crate) obligation_id: String, - #[cultcache(key = 6)] - pub(crate) body_observation_id: String, - #[cultcache(key = 7)] - pub(crate) body_generation: u64, - #[cultcache(key = 8)] - pub(crate) manifest_root_sha256: String, - #[cultcache(key = 9)] - pub(crate) status: String, - #[cultcache(key = 10)] - pub(crate) executor_id: String, - #[cultcache(key = 11)] - pub(crate) executor_incarnation: String, - #[cultcache(key = 12, default)] - pub(crate) managed_process_launch_id: String, - #[cultcache(key = 13, default)] - termination_evidence_id: Option, - #[cultcache(key = 14, default)] - pub(crate) termination_evidence_digest: Option, - #[cultcache(key = 15, default)] - pub(crate) recovery_receipt_id: Option, - #[cultcache(key = 16, default)] - pub(crate) recovery_receipt_digest: Option, -} - -pub(crate) fn validate_projection_claim(claim: &WorkspaceCoverageProjectionClaim) -> Result<()> { - if !matches!( - claim.schema_version.as_str(), - CLAIM_SCHEMA | CLAIM_SCHEMA_V2 | CLAIM_SCHEMA_V3 - ) || claim.claim_id.trim().is_empty() - || claim.claim_epoch == 0 - || claim.plan_id.trim().is_empty() - || claim.attempt_id.trim().is_empty() - || claim.obligation_id.trim().is_empty() - || claim.body_observation_id.trim().is_empty() - || claim.manifest_root_sha256.trim().is_empty() - || claim.executor_id.trim().is_empty() - || claim.executor_incarnation.trim().is_empty() - || claim.managed_process_launch_id.trim().is_empty() - || !matches!(claim.status.as_str(), "running" | "failed" | "succeeded") - { - bail!("invalid workspace coverage projection claim"); - } - match claim.status.as_str() { - "failed" if claim.schema_version == CLAIM_SCHEMA_V2 => { - validate_terminal_evidence( - &claim.termination_evidence_id, - &claim.termination_evidence_digest, - )?; - } - _ if claim.termination_evidence_id.is_some() - || claim.termination_evidence_digest.is_some() => - { - bail!("workspace coverage claim has misplaced termination evidence") - } - _ => {} - } - if claim.schema_version == CLAIM_SCHEMA_V2 && claim.status != "failed" { - bail!("workspace coverage recovery claim schema is terminal-only"); - } - match claim.schema_version.as_str() { - CLAIM_SCHEMA - if claim.recovery_receipt_id.is_some() || claim.recovery_receipt_digest.is_some() => - { - bail!("ordinary workspace coverage claim cites recovery evidence") - } - CLAIM_SCHEMA_V2 | CLAIM_SCHEMA_V3 => { - validate_terminal_evidence(&claim.recovery_receipt_id, &claim.recovery_receipt_digest)? - } - _ => {} - } - Ok(()) -} - -pub(crate) fn validate_projection_attempt( - attempt: &WorkspaceCoverageProjectionAttempt, -) -> Result<()> { - if !matches!( - attempt.schema_version.as_str(), - ATTEMPT_SCHEMA | ATTEMPT_SCHEMA_V2 | ATTEMPT_SCHEMA_V3 - ) || attempt.attempt_id.trim().is_empty() - || attempt.claim_id.trim().is_empty() - || attempt.claim_epoch == 0 - || attempt.plan_id.trim().is_empty() - || attempt.started_at.trim().is_empty() - || attempt.executor_id.trim().is_empty() - || attempt.executor_incarnation.trim().is_empty() - || attempt.managed_process_launch_id.trim().is_empty() - || !matches!(attempt.status.as_str(), "running" | "failed" | "succeeded") - { - bail!("invalid workspace coverage projection attempt"); - } - chrono::DateTime::parse_from_rfc3339(&attempt.started_at)?; - match attempt.status.as_str() { - "running" if attempt.completed_at.is_some() || attempt.error.is_some() => { - bail!("running workspace coverage attempt is already terminal") - } - "failed" - if attempt.completed_at.is_none() - || attempt.error.as_deref().is_none_or(str::is_empty) => - { - bail!("failed workspace coverage attempt lacks terminal evidence") - } - "succeeded" if attempt.completed_at.is_none() || attempt.error.is_some() => { - bail!("successful workspace coverage attempt has invalid terminal evidence") - } - _ => {} - } - if let Some(value) = &attempt.completed_at { - let completed = chrono::DateTime::parse_from_rfc3339(value)?; - let started = chrono::DateTime::parse_from_rfc3339(&attempt.started_at)?; - if completed < started { - bail!("workspace coverage attempt completes before it starts"); - } - } - match attempt.status.as_str() { - "failed" if attempt.schema_version == ATTEMPT_SCHEMA_V2 => { - validate_terminal_evidence( - &attempt.termination_evidence_id, - &attempt.termination_evidence_digest, - )?; - } - _ if attempt.termination_evidence_id.is_some() - || attempt.termination_evidence_digest.is_some() => - { - bail!("workspace coverage attempt has misplaced termination evidence") - } - _ => {} - } - if attempt.schema_version == ATTEMPT_SCHEMA_V2 && attempt.status != "failed" { - bail!("workspace coverage recovery attempt schema is terminal-only"); - } - match attempt.schema_version.as_str() { - ATTEMPT_SCHEMA - if attempt.recovery_receipt_id.is_some() - || attempt.recovery_receipt_digest.is_some() => - { - bail!("ordinary workspace coverage attempt cites recovery evidence") - } - ATTEMPT_SCHEMA_V2 | ATTEMPT_SCHEMA_V3 => validate_terminal_evidence( - &attempt.recovery_receipt_id, - &attempt.recovery_receipt_digest, - )?, - _ => {} - } - Ok(()) -} - -fn validate_terminal_evidence(id: &Option, digest: &Option) -> Result<()> { - let (Some(id), Some(digest)) = (id.as_deref(), digest.as_deref()) else { - bail!("recovered workspace coverage terminal state lacks exact evidence") - }; - let Some(hex) = digest.strip_prefix("sha256-") else { - bail!("recovered workspace coverage terminal evidence is invalid") - }; - if id.trim().is_empty() || hex.len() != 64 || !hex.bytes().all(|b| b.is_ascii_hexdigit()) { - bail!("recovered workspace coverage terminal evidence is invalid") - } - Ok(()) -} - -pub(crate) fn validate_claim_attempt_link( - claim: &WorkspaceCoverageProjectionClaim, - attempt: &WorkspaceCoverageProjectionAttempt, -) -> Result<()> { - validate_projection_claim(claim)?; - validate_projection_attempt(attempt)?; - if claim.claim_id != attempt.claim_id - || !matches!( - ( - claim.schema_version.as_str(), - attempt.schema_version.as_str() - ), - (CLAIM_SCHEMA, ATTEMPT_SCHEMA) - | (CLAIM_SCHEMA_V2, ATTEMPT_SCHEMA_V2) - | (CLAIM_SCHEMA_V3, ATTEMPT_SCHEMA_V3) - ) - || claim.claim_epoch != attempt.claim_epoch - || claim.attempt_id != attempt.attempt_id - || claim.plan_id != attempt.plan_id - || claim.status != attempt.status - || claim.executor_id != attempt.executor_id - || claim.executor_incarnation != attempt.executor_incarnation - || claim.managed_process_launch_id != attempt.managed_process_launch_id - || claim.termination_evidence_id != attempt.termination_evidence_id - || claim.termination_evidence_digest != attempt.termination_evidence_digest - || claim.recovery_receipt_id != attempt.recovery_receipt_id - || claim.recovery_receipt_digest != attempt.recovery_receipt_digest - { - bail!("workspace coverage claim/attempt authority is split"); - } - Ok(()) -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_projection_attempt", - schema = "WorkspaceCoverageProjectionAttempt" -)] -pub(crate) struct WorkspaceCoverageProjectionAttempt { - #[cultcache(key = 0)] - pub(crate) schema_version: String, - #[cultcache(key = 1)] - pub(crate) attempt_id: String, - #[cultcache(key = 2)] - pub(crate) claim_id: String, - #[cultcache(key = 3)] - pub(crate) claim_epoch: u64, - #[cultcache(key = 4)] - pub(crate) plan_id: String, - #[cultcache(key = 5)] - pub(crate) status: String, - #[cultcache(key = 6)] - pub(crate) started_at: String, - #[cultcache(key = 7)] - pub(crate) completed_at: Option, - #[cultcache(key = 8)] - pub(crate) error: Option, - #[cultcache(key = 9)] - pub(crate) executor_id: String, - #[cultcache(key = 10)] - pub(crate) executor_incarnation: String, - #[cultcache(key = 11)] - pub(crate) managed_process_launch_id: String, - #[cultcache(key = 12, default)] - pub(crate) termination_evidence_id: Option, - #[cultcache(key = 13, default)] - pub(crate) termination_evidence_digest: Option, - #[cultcache(key = 14, default)] - pub(crate) recovery_receipt_id: Option, - #[cultcache(key = 15, default)] - pub(crate) recovery_receipt_digest: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_recovery_receipt", - schema = "WorkspaceCoverageRecoveryReceipt" -)] -struct WorkspaceCoverageRecoveryReceipt { - #[cultcache(key = 0)] - schema_version: String, - #[cultcache(key = 1)] - recovery_id: String, - #[cultcache(key = 2)] - old_claim_id: String, - #[cultcache(key = 3)] - old_attempt_id: String, - #[cultcache(key = 4)] - old_claim_epoch: u64, - #[cultcache(key = 5)] - termination_id: String, - #[cultcache(key = 6)] - termination_envelope_digest: String, - #[cultcache(key = 7)] - replacement_launch_id: String, - #[cultcache(key = 8)] - replacement_launch_envelope_digest: String, - #[cultcache(key = 9)] - ready_heartbeat_id: String, - #[cultcache(key = 10)] - ready_heartbeat_envelope_digest: String, - #[cultcache(key = 11)] - new_claim_id: String, - #[cultcache(key = 12)] - new_attempt_id: String, - #[cultcache(key = 13)] - new_claim_epoch: u64, - #[cultcache(key = 14)] - recovered_at_utc: String, - #[cultcache(key = 15)] - old_launch_id: String, -} - -fn validate_recovery_receipt(receipt: &WorkspaceCoverageRecoveryReceipt) -> Result<()> { - if receipt.schema_version != RECOVERY_SCHEMA - || receipt.recovery_id.trim().is_empty() - || receipt.old_claim_id.trim().is_empty() - || receipt.old_attempt_id.trim().is_empty() - || receipt.old_launch_id.trim().is_empty() - || receipt.old_claim_epoch == 0 - || receipt.replacement_launch_id.trim().is_empty() - || receipt.ready_heartbeat_id.trim().is_empty() - || receipt.new_claim_id.trim().is_empty() - || receipt.new_attempt_id.trim().is_empty() - || receipt.old_claim_epoch.checked_add(1) != Some(receipt.new_claim_epoch) - { - bail!("invalid workspace coverage recovery receipt"); - } - validate_terminal_evidence( - &Some(receipt.termination_id.clone()), - &Some(receipt.termination_envelope_digest.clone()), - )?; - validate_terminal_evidence( - &Some(receipt.replacement_launch_id.clone()), - &Some(receipt.replacement_launch_envelope_digest.clone()), - )?; - validate_terminal_evidence( - &Some(receipt.ready_heartbeat_id.clone()), - &Some(receipt.ready_heartbeat_envelope_digest.clone()), - )?; - chrono::DateTime::parse_from_rfc3339(&receipt.recovered_at_utc)?; - Ok(()) -} - -fn cultcache_envelope_digest(value: &CultCacheEnvelope) -> String { - let mut digest = Sha256::new(); - digest.update(value.r#type.as_bytes()); - digest.update([0]); - digest.update(value.key.as_bytes()); - digest.update([0]); - digest.update(&value.payload); - format!("sha256-{:x}", digest.finalize()) -} - -pub fn authenticate_workspace_coverage_recovery_receipt( - runtime_store: impl AsRef, - cultmesh_store: impl AsRef, - runtime_id: &str, - host: &HostIncarnationIdentityEntry, - recovery_id: &str, - expected_digest: &str, -) -> Result<()> { - let coverage = crate::open_workspace_coverage_authority(runtime_store)?; - let opening = coverage.store.pull_all()?; - let receipt_env = find(&opening, RECOVERY_TYPE, recovery_id) - .ok_or_else(|| anyhow!("workspace coverage recovery receipt is absent"))?; - if cultcache_envelope_digest(receipt_env) != expected_digest { - bail!("workspace coverage recovery receipt digest disagrees with authority"); - } - let receipt: WorkspaceCoverageRecoveryReceipt = decode(receipt_env)?; - validate_recovery_receipt(&receipt)?; - if receipt.recovery_id != recovery_id { - bail!("workspace coverage recovery receipt key disagrees with payload"); - } - let (_, termination_digest) = authenticate_workspace_coverage_termination_with_envelope_digest( - cultmesh_store.as_ref(), - runtime_id, - &receipt.old_launch_id, - host, - )?; - let (replacement_launch, replacement_launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - cultmesh_store.as_ref(), - runtime_id, - &receipt.replacement_launch_id, - host, - )?; - let (ready, ready_digest) = - authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest( - cultmesh_store.as_ref(), - runtime_id, - &receipt.ready_heartbeat_id, - host, - )?; - authenticate_workspace_coverage_replacement_lineage( - cultmesh_store.as_ref(), - runtime_id, - &receipt.old_launch_id, - &receipt.replacement_launch_id, - host, - )?; - let latest = load_latest_workspace_coverage_provider_heartbeat( - cultmesh_store, - runtime_id, - &receipt.replacement_launch_id, - )? - .ok_or_else(|| anyhow!("workspace coverage recovery receipt has no current heartbeat"))?; - if termination_digest != receipt.termination_envelope_digest - || replacement_launch_digest != receipt.replacement_launch_envelope_digest - || ready_digest != receipt.ready_heartbeat_envelope_digest - || replacement_launch.launch_id != receipt.replacement_launch_id - || ready.launch_id != receipt.replacement_launch_id - || ready.status != "ready" - || latest.sequence < ready.sequence - || (latest.sequence == ready.sequence && latest.heartbeat_id != ready.heartbeat_id) - { - bail!("workspace coverage recovery receipt external evidence has moved or disagrees"); - } - let claim_env = opening - .iter() - .filter(|entry| entry.r#type == CLAIM_TYPE) - .find(|entry| { - decode::(entry) - .is_ok_and(|claim| claim.claim_id == receipt.new_claim_id) - }) - .ok_or_else(|| anyhow!("workspace coverage recovered claim is absent"))?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &claim.attempt_id) - .ok_or_else(|| anyhow!("workspace coverage recovered attempt is absent"))?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_claim_attempt_link(&claim, &attempt)?; - if claim.claim_id != receipt.new_claim_id - || attempt.attempt_id != receipt.new_attempt_id - || claim.claim_epoch != receipt.new_claim_epoch - || claim.recovery_receipt_id.as_deref() != Some(recovery_id) - || claim.recovery_receipt_digest.as_deref() != Some(expected_digest) - { - bail!("workspace coverage recovery receipt disagrees with current Body authority"); - } - Ok(()) -} - -#[derive(Clone, Debug)] -pub(crate) struct WorkspaceCoveragePreparedPoint { - pub point_id: String, - pub text: String, -} - -#[derive(Clone, Debug)] -pub(crate) struct PreparedWorkspaceCoverageProjection { - pub body_store: PathBuf, - pub basis: RepositoryBodyObservationBasis, - pub obligation: WorkspaceCoverageObligation, - pub plan: WorkspaceCoverageProjectionPlan, - pub points: Vec, -} - -#[derive(Clone, Debug)] -pub(crate) struct WorkspaceCoverageAcquisition { - pub body_store: PathBuf, - pub coverage_store: OwnedRedbMessagePackBackingStore, - pub claim_key: String, - pub obligation: WorkspaceCoverageObligation, - pub plan: WorkspaceCoverageProjectionPlan, - pub claim: WorkspaceCoverageProjectionClaim, - pub attempt: WorkspaceCoverageProjectionAttempt, - prior_head: Option, -} - -pub(crate) fn workspace_coverage_claim_key( - body_observation_id: &str, - body_generation: u64, -) -> String { - format!("current/{body_generation}/{body_observation_id}") -} - -#[derive(Clone, Debug)] -pub(crate) enum WorkspaceCoverageAcquireResult { - Current(WorkspaceCoverageReceipt), - Contended, - Acquired(WorkspaceCoverageAcquisition), -} - -pub(crate) enum WorkspaceCoverageCurrentState { - Current(WorkspaceCoverageReceipt), - NeedsPreparation, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageTerminalAuthority { - pub body_observation_id: String, - pub body_generation: u64, - pub plan_id: String, - pub claim_id: String, - pub claim_epoch: u64, - pub managed_process_launch_id: String, - pub receipt_id: String, -} - -/// Reads the provider-owned terminal authority used by deployment health. -/// This deliberately does not re-read Qdrant: terminal receipt admission -/// already performed the whole-collection readback. Mind readiness owns the -/// stronger live query-evidence join. -pub fn authenticate_current_workspace_coverage_terminal_authority( - runtime_store: &Path, -) -> Result> { - let coverage = crate::open_workspace_coverage_authority(runtime_store)?; - authenticate_current_workspace_coverage_terminal_authority_with_store( - runtime_store, - &coverage.store, - ) -} - -pub(crate) fn authenticate_current_workspace_coverage_terminal_authority_with_store( - runtime_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, -) -> Result> { - let basis = crate::load_current_runtime_repository_body_basis(runtime_store)?; - let route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - let body_opening = SingleFileMessagePackBackingStore::new(&route.body_store_path).pull_all()?; - let body_authority = exact_body_authority(&body_opening, &basis)?; - let opening = coverage_store.pull_all()?; - let Some(head_env) = find(&opening, HEAD_TYPE, HEAD_KEY) else { - return Ok(None); - }; - let head: WorkspaceCoverageHead = decode(head_env)?; - let obligation: WorkspaceCoverageObligation = decode( - find(&opening, OBLIGATION_TYPE, &head.obligation_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing obligation"))?, - )?; - let plan: WorkspaceCoverageProjectionPlan = decode( - find(&opening, PLAN_TYPE, &head.plan_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing plan"))?, - )?; - let receipt: WorkspaceCoverageReceipt = decode( - find(&opening, RECEIPT_TYPE, &head.receipt_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing receipt"))?, - )?; - let Some(claim_env) = find( - &opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&basis.observation_id, basis.generation), - ) else { - return Ok(None); - }; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt: WorkspaceCoverageProjectionAttempt = decode( - find(&opening, ATTEMPT_TYPE, &claim.attempt_id) - .ok_or_else(|| anyhow!("current workspace coverage lost its projection attempt"))?, - )?; - validate_workspace_coverage_head(&obligation, &plan, &receipt, &head)?; - validate_claim_attempt_link(&claim, &attempt)?; - 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))?) - ); - let exact = head.workspace_id == basis.workspace_id - && head.body_observation_id == basis.observation_id - && head.body_generation == basis.generation - && head.manifest_root_sha256 == basis.manifest_root_sha256 - && obligation.runtime_id == basis.runtime_id - && obligation.workspace_id == basis.workspace_id - && obligation.swarm_id == basis.swarm_id - && obligation.body_binding_sha256 == basis.body_binding_sha256 - && obligation.body_observation_id == basis.observation_id - && obligation.body_generation == basis.generation - && obligation.manifest_root_sha256 == basis.manifest_root_sha256 - && obligation.policy_id == policy.policy_id - && obligation.policy_sha256 == policy_sha256 - && plan.projection_schema_version == PROJECTION_SCHEMA - && plan.chunker_id == CHUNKER_ID - && claim.status == "succeeded" - && attempt.status == "succeeded" - && claim.claim_id == receipt.claim_id - && claim.claim_epoch == receipt.claim_epoch - && claim.plan_id == plan.plan_id - && claim.obligation_id == obligation.obligation_id; - if !exact { - return Ok(None); - } - exact_obligation_body_authority(&body_opening, &obligation)?; - let closing_body = SingleFileMessagePackBackingStore::new(&route.body_store_path).pull_all()?; - for expected in body_authority { - if find(&closing_body, &expected.r#type, &expected.key) != Some(&expected) { - return Ok(None); - } - } - Ok(Some(WorkspaceCoverageTerminalAuthority { - body_observation_id: basis.observation_id, - body_generation: basis.generation, - plan_id: plan.plan_id, - claim_id: claim.claim_id, - claim_epoch: claim.claim_epoch, - managed_process_launch_id: claim.managed_process_launch_id, - receipt_id: receipt.receipt_id, - })) -} - -fn collection_compatibility(plan: &WorkspaceCoverageProjectionPlan) -> CollectionCompatibility { - CollectionCompatibility { - managed_by: "epiphany-workspace-coverage-projector".into(), - corpus_kind: "repository_body_workspace_coverage".into(), - schema_version: 0, - projection_version: plan.plan_id.clone(), - embedding_provider_id: plan.embedding_provider_id.clone(), - embedding_model: plan.embedding_model.clone(), - vector_size: plan.vector_dimensions as usize, - } -} - -/// Derives disposable Qdrant collections exclusively from sealed Body-store -/// history. Every attempt is validated before any candidate is returned: one -/// malformed historical row refuses the whole GC pass. -pub(crate) fn workspace_coverage_retirement_candidates( - coverage_store: &OwnedRedbMessagePackBackingStore, -) -> Result> { - let opening = coverage_store.pull_all()?; - - let attempts = opening - .iter() - .filter(|entry| entry.r#type == ATTEMPT_TYPE) - .map(decode::) - .collect::>>()?; - - let mut protected_collection = None; - if let Some(head_env) = find(&opening, HEAD_TYPE, HEAD_KEY) { - let head: WorkspaceCoverageHead = decode(head_env)?; - let obligation: WorkspaceCoverageObligation = decode( - find(&opening, OBLIGATION_TYPE, &head.obligation_id) - .ok_or_else(|| anyhow!("workspace coverage head names missing obligation"))?, - )?; - let plan: WorkspaceCoverageProjectionPlan = decode( - find(&opening, PLAN_TYPE, &head.plan_id) - .ok_or_else(|| anyhow!("workspace coverage head names missing plan"))?, - )?; - let receipt: WorkspaceCoverageReceipt = decode( - find(&opening, RECEIPT_TYPE, &head.receipt_id) - .ok_or_else(|| anyhow!("workspace coverage head names missing receipt"))?, - )?; - validate_workspace_coverage_head(&obligation, &plan, &receipt, &head)?; - protected_collection = Some(receipt.collection_name); - } - - for claim_env in opening.iter().filter(|entry| entry.r#type == CLAIM_TYPE) { - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt = attempts - .iter() - .find(|attempt| attempt.attempt_id == claim.attempt_id) - .ok_or_else(|| anyhow!("workspace coverage claim names missing attempt"))?; - validate_claim_attempt_link(&claim, attempt)?; - let plan: WorkspaceCoverageProjectionPlan = decode( - find(&opening, PLAN_TYPE, &claim.plan_id) - .ok_or_else(|| anyhow!("workspace coverage claim names missing plan"))?, - )?; - if plan.obligation_id != claim.obligation_id { - bail!("workspace coverage claim/plan authority is split"); - } - } - - let mut candidates = std::collections::BTreeMap::new(); - for attempt in attempts { - validate_projection_attempt(&attempt)?; - let plan: WorkspaceCoverageProjectionPlan = decode( - find(&opening, PLAN_TYPE, &attempt.plan_id) - .ok_or_else(|| anyhow!("workspace coverage attempt names missing plan"))?, - )?; - let obligation: WorkspaceCoverageObligation = decode( - find(&opening, OBLIGATION_TYPE, &plan.obligation_id) - .ok_or_else(|| anyhow!("workspace coverage plan names missing obligation"))?, - )?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - if attempt.status == "running" { - continue; - } - let name = workspace_coverage_execution_collection( - &plan.plan_id, - &attempt.claim_id, - attempt.claim_epoch, - )?; - if protected_collection.as_deref() == Some(&name) { - continue; - } - candidates.insert( - name.clone(), - WorkspaceCoverageRetirementCandidate { - collection_name: name, - compatibility: collection_compatibility(&plan), - claim_id: attempt.claim_id.clone(), - attempt_id: attempt.attempt_id.clone(), - plan_id: attempt.plan_id.clone(), - body_observation_id: obligation.body_observation_id, - body_generation: obligation.body_generation, - }, - ); - } - Ok(candidates.into_values().collect()) -} - -pub(crate) fn retire_workspace_coverage_collections( - coverage_authority: &crate::WorkspaceCoverageAuthority, - port: &mut impl WorkspaceCoverageRetirementPort, -) -> Result { - let candidates = workspace_coverage_retirement_candidates(&coverage_authority.store)?; - for candidate in &candidates { - port.retire_exact(&candidate.collection_name, &candidate.compatibility)?; - let compatibility_sha256 = format!( - "sha256-{:x}", - Sha256::digest(rmp_serde::to_vec_named(&candidate.compatibility)?) - ); - let evidence = WorkspaceCoverageCollectionRetirementEvidence { - schema_version: COLLECTION_RETIREMENT_EVIDENCE_SCHEMA.into(), - collection_name: candidate.collection_name.clone(), - collection_compatibility_sha256: compatibility_sha256, - claim_id: candidate.claim_id.clone(), - attempt_id: candidate.attempt_id.clone(), - plan_id: candidate.plan_id.clone(), - body_observation_id: candidate.body_observation_id.clone(), - body_generation: candidate.body_generation, - runtime_id: coverage_authority.store_binding.runtime_id.clone(), - workspace_id: coverage_authority.store_binding.workspace_id.clone(), - coverage_binding_id: coverage_authority.store_binding.binding_id.clone(), - coverage_binding_envelope_sha256: coverage_authority - .store_binding_envelope_sha256 - .clone(), - coverage_store_file_identity: coverage_authority.store.file_identity().into(), - observed_result: "retired-or-absent".into(), - observed_at_utc: chrono::Utc::now().to_rfc3339(), - }; - validate_collection_retirement_evidence(&evidence)?; - let key = candidate.collection_name.clone(); - let replacement = envelope(COLLECTION_RETIREMENT_EVIDENCE_TYPE, &key, &evidence)?; - let opening = coverage_authority.store.pull_all()?; - if let Some(existing) = find(&opening, COLLECTION_RETIREMENT_EVIDENCE_TYPE, &key) { - let prior: WorkspaceCoverageCollectionRetirementEvidence = decode(existing)?; - validate_collection_retirement_evidence(&prior)?; - if prior.collection_name != evidence.collection_name - || prior.collection_compatibility_sha256 != evidence.collection_compatibility_sha256 - || prior.claim_id != evidence.claim_id - || prior.attempt_id != evidence.attempt_id - || prior.plan_id != evidence.plan_id - || prior.body_observation_id != evidence.body_observation_id - || prior.body_generation != evidence.body_generation - || prior.runtime_id != evidence.runtime_id - || prior.workspace_id != evidence.workspace_id - || prior.coverage_binding_id != evidence.coverage_binding_id - || prior.coverage_binding_envelope_sha256 - != evidence.coverage_binding_envelope_sha256 - || prior.coverage_store_file_identity != evidence.coverage_store_file_identity - || prior.observed_result != evidence.observed_result - { - bail!("workspace coverage retirement evidence identity was substituted"); - } - } else if !coverage_authority - .store - .insert_entry_if_absent(replacement)? - { - bail!("workspace coverage retirement evidence lost exact insertion"); - } - } - Ok(candidates.len()) -} - -/// Classifies the persisted projection using typed authority only. This is the -/// service's idle path: no Repository Body file is opened or materialized. -pub(crate) fn classify_current_workspace_coverage( - runtime_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - basis: &RepositoryBodyObservationBasis, - embedding_provider_id: &str, - embedding_model: &str, - vector_dimensions: u32, -) -> Result { - if embedding_provider_id.trim().is_empty() - || embedding_model.trim().is_empty() - || vector_dimensions == 0 - { - bail!("workspace coverage classification requires exact embedding identity"); - } - let route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - let body_opening = SingleFileMessagePackBackingStore::new(&route.body_store_path).pull_all()?; - let body_authority = exact_body_authority(&body_opening, basis)?; - let opening = coverage_store.pull_all()?; - let Some(head_env) = find(&opening, HEAD_TYPE, HEAD_KEY) else { - return Ok(WorkspaceCoverageCurrentState::NeedsPreparation); - }; - let head: WorkspaceCoverageHead = decode(head_env)?; - let obligation: WorkspaceCoverageObligation = decode( - find( - &opening, - "gamecult.epiphany.workspace_coverage_obligation", - &head.obligation_id, - ) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing obligation"))?, - )?; - let plan: WorkspaceCoverageProjectionPlan = decode( - find( - &opening, - "gamecult.epiphany.workspace_coverage_projection_plan", - &head.plan_id, - ) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing plan"))?, - )?; - let receipt: WorkspaceCoverageReceipt = decode( - find(&opening, RECEIPT_TYPE, &head.receipt_id) - .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(WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES)?; - let policy_sha256 = format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(&policy).map_err(|error| anyhow!(error))?) - ); - let exact = head.workspace_id == basis.workspace_id - && head.body_observation_id == basis.observation_id - && head.body_generation == basis.generation - && head.manifest_root_sha256 == basis.manifest_root_sha256 - && obligation.workspace_id == basis.workspace_id - && obligation.swarm_id == basis.swarm_id - && obligation.runtime_id == basis.runtime_id - && obligation.body_binding_sha256 == basis.body_binding_sha256 - && obligation.body_observation_id == basis.observation_id - && obligation.body_generation == basis.generation - && obligation.manifest_root_sha256 == basis.manifest_root_sha256 - && obligation.policy_id == policy.policy_id - && obligation.policy_sha256 == policy_sha256 - && plan.projection_schema_version == PROJECTION_SCHEMA - && plan.chunker_id == CHUNKER_ID - && plan.embedding_provider_id == embedding_provider_id - && plan.embedding_model == embedding_model - && plan.vector_dimensions == vector_dimensions - && receipt.embedding_provider_id == embedding_provider_id - && receipt.embedding_model == embedding_model - && receipt.vector_dimensions == vector_dimensions; - if !exact { - return Ok(WorkspaceCoverageCurrentState::NeedsPreparation); - } - let closing_body = SingleFileMessagePackBackingStore::new(&route.body_store_path).pull_all()?; - for expected in body_authority { - if find(&closing_body, &expected.r#type, &expected.key) != Some(&expected) { - return Ok(WorkspaceCoverageCurrentState::NeedsPreparation); - } - } - Ok(WorkspaceCoverageCurrentState::Current(receipt)) -} - -/// Authenticates and re-observes the exact current workspace projection. -/// -/// A persisted coverage head is historical evidence only. This reader returns -/// evidence only after the current succeeded claim/attempt chain and the live -/// Qdrant payload/vector bindings agree with that head's sealed plan. -#[allow(dead_code)] // Wired by the Mind readiness join, never by the projector. -pub(crate) fn observe_current_workspace_coverage_evidence( - runtime_store: &Path, - basis: &RepositoryBodyObservationBasis, - policy: &WorkspaceCoveragePolicy, - embedding_provider_id: &str, - embedding_model: &str, - vector_dimensions: u32, - port: &mut impl WorkspaceCoverageEvidencePort, -) -> Result> { - let coverage = crate::open_workspace_coverage_authority(runtime_store)?; - observe_current_workspace_coverage_evidence_with_store( - runtime_store, - &coverage.store, - basis, - policy, - embedding_provider_id, - embedding_model, - vector_dimensions, - port, - ) -} - -pub(crate) fn observe_current_workspace_coverage_evidence_with_store( - runtime_store: &Path, - coverage_store: &OwnedRedbMessagePackBackingStore, - basis: &RepositoryBodyObservationBasis, - policy: &WorkspaceCoveragePolicy, - embedding_provider_id: &str, - embedding_model: &str, - vector_dimensions: u32, - port: &mut impl WorkspaceCoverageEvidencePort, -) -> Result> { - if policy.schema_version != crate::WORKSPACE_COVERAGE_POLICY_SCHEMA_VERSION - || policy.policy_id.trim().is_empty() - || policy.maximum_file_bytes == 0 - || embedding_provider_id.trim().is_empty() - || embedding_model.trim().is_empty() - || vector_dimensions == 0 - { - bail!("workspace coverage evidence requires an exact policy and embedding identity"); - } - let route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - let body_opening = SingleFileMessagePackBackingStore::new(&route.body_store_path).pull_all()?; - exact_body_authority(&body_opening, basis)?; - let opening = coverage_store.pull_all()?; - let Some(head_env) = find(&opening, HEAD_TYPE, HEAD_KEY) else { - return Ok(None); - }; - let head: WorkspaceCoverageHead = decode(head_env)?; - let obligation_env = find(&opening, OBLIGATION_TYPE, &head.obligation_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing obligation"))?; - let plan_env = find(&opening, PLAN_TYPE, &head.plan_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing plan"))?; - let receipt_env = find(&opening, RECEIPT_TYPE, &head.receipt_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing receipt"))?; - let claim_env = find( - &opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&basis.observation_id, basis.generation), - ) - .ok_or_else(|| anyhow!("current workspace coverage lost its projection claim"))?; - let obligation: WorkspaceCoverageObligation = decode(obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(plan_env)?; - let receipt: WorkspaceCoverageReceipt = decode(receipt_env)?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &claim.attempt_id) - .ok_or_else(|| anyhow!("current workspace coverage lost its projection attempt"))?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_workspace_coverage_head(&obligation, &plan, &receipt, &head)?; - validate_claim_attempt_link(&claim, &attempt)?; - - let policy_sha256 = format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(policy).map_err(|error| anyhow!(error))?) - ); - let exact = head.workspace_id == basis.workspace_id - && head.body_observation_id == basis.observation_id - && head.body_generation == basis.generation - && head.manifest_root_sha256 == basis.manifest_root_sha256 - && obligation.workspace_id == basis.workspace_id - && obligation.swarm_id == basis.swarm_id - && obligation.runtime_id == basis.runtime_id - && obligation.body_binding_sha256 == basis.body_binding_sha256 - && obligation.body_observation_id == basis.observation_id - && obligation.body_generation == basis.generation - && obligation.manifest_root_sha256 == basis.manifest_root_sha256 - && obligation.policy_id == policy.policy_id - && obligation.policy_sha256 == policy_sha256 - && plan.projection_schema_version == PROJECTION_SCHEMA - && plan.chunker_id == CHUNKER_ID - && plan.embedding_provider_id == embedding_provider_id - && plan.embedding_model == embedding_model - && plan.vector_dimensions == vector_dimensions - && receipt.embedding_provider_id == embedding_provider_id - && receipt.embedding_model == embedding_model - && receipt.vector_dimensions == vector_dimensions - && claim.status == "succeeded" - && claim.claim_id == receipt.claim_id - && claim.claim_epoch == receipt.claim_epoch - && claim.plan_id == plan.plan_id - && claim.obligation_id == obligation.obligation_id - && claim.body_observation_id == obligation.body_observation_id - && claim.body_generation == obligation.body_generation - && claim.manifest_root_sha256 == obligation.manifest_root_sha256; - if !exact { - return Ok(None); - } - - port.authenticate_exact_collection(&receipt.collection_name, &collection_compatibility(&plan))?; - let observed = observe_sealed_bindings( - &obligation, - &plan, - &receipt.collection_name, - port.observe_all_for_evidence(&receipt.collection_name)?, - None, - )?; - if observed.point_count != receipt.observed_point_count - || observed.point_set_sha256 != receipt.observed_point_set_sha256 - || observed.point_binding_set_sha256 != receipt.observed_point_binding_set_sha256 - || observed.vector_binding_set_sha256 != receipt.observed_vector_binding_set_sha256 - { - bail!("live workspace coverage observation disagrees with its exact receipt"); - } - - // Qdrant observation is outside the Body-store lock domain. Close the - // mixed-epoch window by reopening both the runtime route and Body store, - // then require every authority envelope consumed above to remain exact. - let closing_route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime lost its repository Body-store binding"))?; - if closing_route != route { - return Ok(None); - } - let closing_body = - SingleFileMessagePackBackingStore::new(&closing_route.body_store_path).pull_all()?; - let closing = coverage_store.pull_all()?; - for expected in body_opening.iter().filter(|entry| { - matches!( - entry.r#type.as_str(), - BODY_BINDING_TYPE | BODY_HEAD_TYPE | BODY_OBSERVATION_TYPE | BODY_MANIFEST_TYPE - ) - }) { - if find(&closing_body, &expected.r#type, &expected.key) != Some(expected) { - return Ok(None); - } - } - for expected in [ - head_env, - obligation_env, - plan_env, - claim_env, - attempt_env, - receipt_env, - ] { - if find(&closing, &expected.r#type, &expected.key) != Some(expected) { - return Ok(None); - } - } - Ok(Some(WorkspaceCoverageReadinessEvidence { - workspace_id: obligation.workspace_id, - body_binding_sha256: obligation.body_binding_sha256, - manifest_root_sha256: obligation.manifest_root_sha256, - policy_id: obligation.policy_id, - policy_sha256: obligation.policy_sha256, - obligation_id: obligation.obligation_id, - obligation_envelope_digest: cultcache_envelope_digest(obligation_env), - plan_id: plan.plan_id, - plan_envelope_digest: cultcache_envelope_digest(plan_env), - claim_id: claim.claim_id, - claim_epoch: claim.claim_epoch, - claim_envelope_digest: cultcache_envelope_digest(claim_env), - attempt_id: attempt.attempt_id, - attempt_envelope_digest: cultcache_envelope_digest(attempt_env), - receipt_id: receipt.receipt_id, - receipt_envelope_digest: cultcache_envelope_digest(receipt_env), - head_envelope_digest: cultcache_envelope_digest(head_env), - collection_name: observed.collection_name, - observed_point_count: observed.point_count, - observed_point_set_sha256: observed.point_set_sha256, - observed_point_binding_set_sha256: observed.point_binding_set_sha256, - observed_vector_binding_set_sha256: observed.vector_binding_set_sha256, - })) -} - -pub(crate) fn prepare_workspace_coverage_projection( - body: &RepositoryBodyReadSession, - embedding_provider_id: &str, - embedding_model: &str, - vector_dimensions: u32, -) -> Result { - let basis = body.basis(); - 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(), - &policy, - )?; - let mut verified_text = Vec::new(); - let mut non_utf8_paths = Vec::new(); - for entry in &raw_obligation.classifications { - if !matches!( - entry.disposition, - crate::WorkspaceCoverageDisposition::IncludeRegularFile - ) { - continue; - } - let verified = body.read_regular_file(&entry.path)?; - if verified.relative_path != entry.path || verified.raw_sha256 != entry.raw_sha256 { - bail!("verified Body bytes lost their manifest identity"); - } - if std::str::from_utf8(&verified.bytes).is_ok() { - verified_text.push(verified); - } else { - non_utf8_paths.push(entry.path.clone()); - } - } - let obligation = refine_workspace_coverage_obligation_utf8(&raw_obligation, &non_utf8_paths)?; - let mut descriptors = Vec::new(); - let mut prepared_points = Vec::new(); - for verified in verified_text { - let file_descriptors = chunk_descriptors( - &verified.relative_path, - &verified.raw_sha256, - &verified.bytes, - )?; - for descriptor in &file_descriptors { - prepared_points.push(WorkspaceCoveragePreparedPoint { - point_id: String::new(), - text: std::str::from_utf8( - &verified.bytes[descriptor.byte_start as usize..descriptor.byte_end as usize], - )? - .to_string(), - }); - } - descriptors.extend(file_descriptors); - } - let plan = derive_workspace_coverage_projection_plan( - &obligation, - PROJECTION_SCHEMA, - CHUNKER_ID, - embedding_provider_id, - embedding_model, - vector_dimensions, - descriptors, - )?; - let body_store = body.body_store().to_path_buf(); - if prepared_points.len() != plan.planned_points.len() { - bail!("prepared workspace text lost its sealed plan cardinality"); - } - for (prepared, planned) in prepared_points.iter_mut().zip(&plan.planned_points) { - prepared.point_id = planned.point_id.clone(); - if format!("{:x}", Sha256::digest(prepared.text.as_bytes())) != planned.chunk_sha256 { - bail!("prepared workspace text lost its sealed chunk identity"); - } - } - Ok(PreparedWorkspaceCoverageProjection { - body_store, - basis: basis.clone(), - obligation, - plan, - points: prepared_points, - }) -} - -pub(crate) fn acquire_workspace_coverage_projection( - prepared: &PreparedWorkspaceCoverageProjection, - coverage_store: &OwnedRedbMessagePackBackingStore, - executor_id: &str, - executor_incarnation: &str, - managed_process_launch_id: &str, -) -> Result { - if executor_id.trim().is_empty() - || executor_incarnation.trim().is_empty() - || managed_process_launch_id.trim().is_empty() - { - bail!("workspace coverage acquisition requires exact executor lifecycle identity"); - } - let body_store = prepared.body_store.clone(); - let obligation = prepared.obligation.clone(); - let plan = prepared.plan.clone(); - let body_opening = SingleFileMessagePackBackingStore::new(&body_store).pull_all()?; - let opening = coverage_store.pull_all()?; - let basis = &prepared.basis; - let body_authority = exact_body_authority(&body_opening, basis)?; - if let Some(receipt) = validate_current_projection(&opening, prepared)? { - return Ok(WorkspaceCoverageAcquireResult::Current(receipt)); - } - let claim_key = workspace_coverage_claim_key(&basis.observation_id, basis.generation); - let existing_claim = find(&opening, CLAIM_TYPE, &claim_key); - let claim_epoch = match existing_claim { - Some(envelope) => { - let prior: WorkspaceCoverageProjectionClaim = decode(envelope)?; - validate_projection_claim(&prior)?; - let prior_attempt_env = find(&opening, ATTEMPT_TYPE, &prior.attempt_id) - .ok_or_else(|| anyhow!("existing workspace coverage claim attempt missing"))?; - let prior_attempt: WorkspaceCoverageProjectionAttempt = decode(prior_attempt_env)?; - validate_claim_attempt_link(&prior, &prior_attempt)?; - if prior.status == "running" { - if prior.executor_id == executor_id - && prior.executor_incarnation == executor_incarnation - && prior.managed_process_launch_id == managed_process_launch_id - && prior.plan_id == plan.plan_id - && prior.obligation_id == obligation.obligation_id - && prior.body_observation_id == basis.observation_id - && prior.body_generation == basis.generation - && prior.manifest_root_sha256 == basis.manifest_root_sha256 - { - return Ok(WorkspaceCoverageAcquireResult::Acquired( - WorkspaceCoverageAcquisition { - body_store, - coverage_store: coverage_store.clone(), - claim_key, - obligation, - plan, - claim: prior, - attempt: prior_attempt, - prior_head: find(&opening, HEAD_TYPE, HEAD_KEY).cloned(), - }, - )); - } - return Ok(WorkspaceCoverageAcquireResult::Contended); - } - prior - .claim_epoch - .checked_add(1) - .ok_or_else(|| anyhow!("claim epoch exhausted"))? - } - None => 1, - }; - let claim_id = uuid::Uuid::new_v4().to_string(); - let attempt_id = uuid::Uuid::new_v4().to_string(); - let claim = WorkspaceCoverageProjectionClaim { - schema_version: CLAIM_SCHEMA.into(), - claim_id: claim_id.clone(), - claim_epoch, - plan_id: plan.plan_id.clone(), - attempt_id: attempt_id.clone(), - obligation_id: obligation.obligation_id.clone(), - body_observation_id: basis.observation_id.clone(), - body_generation: basis.generation, - manifest_root_sha256: basis.manifest_root_sha256.clone(), - status: "running".into(), - executor_id: executor_id.into(), - executor_incarnation: executor_incarnation.into(), - managed_process_launch_id: managed_process_launch_id.into(), - termination_evidence_id: None, - termination_evidence_digest: None, - recovery_receipt_id: None, - recovery_receipt_digest: None, - }; - let attempt = WorkspaceCoverageProjectionAttempt { - schema_version: ATTEMPT_SCHEMA.into(), - attempt_id: attempt_id.clone(), - claim_id, - claim_epoch, - plan_id: plan.plan_id.clone(), - status: "running".into(), - started_at: chrono::Utc::now().to_rfc3339(), - completed_at: None, - error: None, - executor_id: executor_id.into(), - executor_incarnation: executor_incarnation.into(), - managed_process_launch_id: managed_process_launch_id.into(), - termination_evidence_id: None, - termination_evidence_digest: None, - recovery_receipt_id: None, - recovery_receipt_digest: None, - }; - let mut expected = Vec::new(); - if let Some(existing) = existing_claim { - expected.push(existing.clone()); - } - let mut replacements = Vec::new(); - let obligation_env = envelope( - "gamecult.epiphany.workspace_coverage_obligation", - &obligation.obligation_id, - &obligation, - )?; - let plan_env = envelope( - "gamecult.epiphany.workspace_coverage_projection_plan", - &plan.plan_id, - &plan, - )?; - preserve_or_insert_immutable(&opening, &mut expected, &mut replacements, obligation_env)?; - preserve_or_insert_immutable(&opening, &mut expected, &mut replacements, plan_env)?; - replacements.push(envelope(CLAIM_TYPE, &claim_key, &claim)?); - replacements.push(envelope(ATTEMPT_TYPE, &attempt_id, &attempt)?); - if !coverage_store.compare_and_swap_batch(&expected, replacements)? { - bail!("workspace coverage acquisition lost exact coverage-store claim CAS"); - } - let closing_body = SingleFileMessagePackBackingStore::new(&body_store).pull_all()?; - for expected in body_authority { - if find(&closing_body, &expected.r#type, &expected.key) != Some(&expected) { - bail!("repository Body changed during workspace coverage acquisition"); - } - } - Ok(WorkspaceCoverageAcquireResult::Acquired( - WorkspaceCoverageAcquisition { - body_store, - coverage_store: coverage_store.clone(), - claim_key, - obligation, - plan, - claim, - attempt, - prior_head: find(&opening, HEAD_TYPE, HEAD_KEY).cloned(), - }, - )) -} - -/// Atomically transfers a projection lease only after CultMesh proves the old -/// process dead and the replacement process ready. This does not launch either -/// process; the supervisor must establish the evidence ordering first. -pub(crate) fn recover_workspace_coverage_projection_with_authority( - coverage: &crate::WorkspaceCoverageAuthority, - runtime_store: impl AsRef, - cultmesh_store: impl AsRef, - runtime_id: &str, - host: &HostIncarnationIdentityEntry, - old_launch_id: &str, - replacement_launch_id: &str, - replacement_ready_heartbeat_id: &str, - expected_old_claim_id: &str, -) -> Result { - let runtime_store = runtime_store.as_ref(); - let body_route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("workspace coverage recovery runtime has no Body-store binding"))?; - if body_route.runtime_id != runtime_id { - bail!("workspace coverage recovery runtime disagrees with its Body route"); - } - let cultmesh_store = cultmesh_store.as_ref(); - let (old_launch, _) = - authenticate_historical_workspace_coverage_managed_process_launch_with_envelope_digest( - cultmesh_store, - runtime_id, - old_launch_id, - host, - )?; - let (termination, termination_digest) = - authenticate_workspace_coverage_termination_with_envelope_digest( - cultmesh_store, - runtime_id, - old_launch_id, - host, - )?; - let (replacement_launch, replacement_launch_digest) = - authenticate_workspace_coverage_managed_process_launch_with_envelope_digest( - cultmesh_store, - runtime_id, - replacement_launch_id, - host, - )?; - let (ready, ready_digest) = - authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest( - cultmesh_store, - runtime_id, - replacement_ready_heartbeat_id, - host, - )?; - authenticate_workspace_coverage_replacement_lineage( - cultmesh_store, - runtime_id, - old_launch_id, - replacement_launch_id, - host, - )?; - let latest = load_latest_workspace_coverage_provider_heartbeat( - cultmesh_store, - runtime_id, - &replacement_launch.launch_id, - )? - .ok_or_else(|| anyhow!("workspace coverage recovery replacement has no current heartbeat"))?; - let (latest, _) = authenticate_workspace_coverage_provider_heartbeat_with_envelope_digest( - cultmesh_store, - runtime_id, - &latest.heartbeat_id, - host, - )?; - let ready_at = chrono::DateTime::parse_from_rfc3339(&ready.observed_at_utc)?; - let latest_at = chrono::DateTime::parse_from_rfc3339(&latest.observed_at_utc)?; - if old_launch.launch_id == replacement_launch.launch_id - || ready.launch_id != replacement_launch.launch_id - || ready.status != "ready" - || ready.sequence == 0 - || latest.launch_id != ready.launch_id - || latest.provider_incarnation_id != ready.provider_incarnation_id - || latest.provider_public_key != ready.provider_public_key - || latest.status != "ready" - || latest.sequence < ready.sequence - || latest_at < ready_at - { - bail!("workspace coverage recovery replacement is not exact and ready"); - } - let terminated_at = chrono::DateTime::parse_from_rfc3339(&termination.observed_at_utc)?; - let replacement_launched_at = - chrono::DateTime::parse_from_rfc3339(&replacement_launch.launched_at_utc)?; - if terminated_at >= replacement_launched_at { - bail!("workspace coverage recovery requires termination before replacement launch"); - } - - let body_store = PathBuf::from(&body_route.body_store_path); - let body_basis = observe_runtime_repository_body_basis(runtime_store)?; - RepositoryBodyReadSession::open(runtime_store, &body_basis)?; - let body_opening = SingleFileMessagePackBackingStore::new(&body_store).pull_all()?; - let body_authority = exact_body_authority(&body_opening, &body_basis)?; - let opening = coverage.store.pull_all()?; - let claim_key = workspace_coverage_claim_key(&body_basis.observation_id, body_basis.generation); - let claim_env = find(&opening, CLAIM_TYPE, &claim_key) - .ok_or_else(|| anyhow!("workspace coverage recovery running claim is absent"))?; - let old_claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &old_claim.attempt_id) - .ok_or_else(|| anyhow!("workspace coverage recovery running attempt is absent"))?; - let old_attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - validate_claim_attempt_link(&old_claim, &old_attempt)?; - // The coverage CAS may have committed before the successor projector could - // publish its claim sight. Replaying the exact host directive must observe - // that committed transfer, not attempt a second transfer or strand recovery. - if old_claim.claim_id != expected_old_claim_id - && let (Some(recovery_id), Some(expected_digest)) = ( - old_claim.recovery_receipt_id.as_deref(), - old_claim.recovery_receipt_digest.as_deref(), - ) - { - let receipt_env = find(&opening, RECOVERY_TYPE, recovery_id) - .ok_or_else(|| anyhow!("recovered successor receipt is absent"))?; - let receipt: WorkspaceCoverageRecoveryReceipt = decode(receipt_env)?; - validate_recovery_receipt(&receipt)?; - let receipt_digest = cultcache_envelope_digest(receipt_env); - if receipt_digest != expected_digest - || receipt.old_claim_id != expected_old_claim_id - || receipt.termination_id != termination.termination_id - || receipt.termination_envelope_digest != termination_digest.as_str() - || receipt.replacement_launch_id != replacement_launch.launch_id - || receipt.replacement_launch_envelope_digest != replacement_launch_digest.as_str() - || receipt.ready_heartbeat_id != ready.heartbeat_id - || receipt.ready_heartbeat_envelope_digest != ready_digest.as_str() - || receipt.new_claim_id != old_claim.claim_id - || receipt.new_attempt_id != old_attempt.attempt_id - || receipt.new_claim_epoch != old_claim.claim_epoch - || old_claim.managed_process_launch_id != replacement_launch.launch_id - || old_claim.executor_incarnation != replacement_launch.provider_incarnation_id - || old_claim.status != "running" - || old_attempt.status != "running" - { - bail!("workspace coverage recovered successor disagrees with exact directive evidence"); - } - return Ok(WorkspaceCoverageRecoveryOutcome { - claim_id: old_claim.claim_id, - claim_epoch: old_claim.claim_epoch, - managed_process_launch_id: old_claim.managed_process_launch_id, - executor_incarnation: old_claim.executor_incarnation, - recovery_receipt_id: recovery_id.to_string(), - recovery_receipt_digest: receipt_digest, - }); - } - if old_claim.schema_version != CLAIM_SCHEMA - || old_attempt.schema_version != ATTEMPT_SCHEMA - || old_claim.status != "running" - || old_claim.claim_id != expected_old_claim_id - || old_claim.managed_process_launch_id != old_launch.launch_id - || old_claim.executor_id != old_launch.provider_daemon_id - || old_claim.executor_incarnation != old_launch.provider_incarnation_id - { - bail!("workspace coverage recovery refuses moved, terminal, legacy, or misbound authority"); - } - - let body_head_env = find(&body_opening, BODY_HEAD_TYPE, BODY_HEAD_KEY) - .ok_or_else(|| anyhow!("current Body head missing"))?; - let body_head: RepositoryBodyHead = decode(body_head_env)?; - if body_head.observation_id != old_claim.body_observation_id - || body_head.generation != old_claim.body_generation - || body_head.manifest_root_sha256 != old_claim.manifest_root_sha256 - { - bail!("workspace coverage recovery refuses moved Body authority"); - } - let obligation_env = find(&opening, OBLIGATION_TYPE, &old_claim.obligation_id) - .cloned() - .ok_or_else(|| anyhow!("projection obligation missing"))?; - let plan_env = find(&opening, PLAN_TYPE, &old_claim.plan_id) - .cloned() - .ok_or_else(|| anyhow!("projection plan missing"))?; - let obligation: WorkspaceCoverageObligation = decode(&obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(&plan_env)?; - validate_workspace_coverage_projection_plan(&obligation, &plan)?; - if plan.plan_id != old_claim.plan_id - || plan.obligation_id != old_claim.obligation_id - || obligation.runtime_id != body_basis.runtime_id - || obligation.swarm_id != body_basis.swarm_id - || obligation.workspace_id != body_basis.workspace_id - || obligation.body_binding_sha256 != body_basis.body_binding_sha256 - || obligation.body_observation_id != body_basis.observation_id - || obligation.body_generation != body_basis.generation - || obligation.manifest_root_sha256 != body_basis.manifest_root_sha256 - || old_claim.body_observation_id != body_basis.observation_id - || old_claim.body_generation != body_basis.generation - || old_claim.manifest_root_sha256 != body_basis.manifest_root_sha256 - { - bail!("workspace coverage recovery refuses substituted plan"); - } - let prior_head = find(&opening, HEAD_TYPE, HEAD_KEY).cloned(); - - let claim_epoch = old_claim - .claim_epoch - .checked_add(1) - .ok_or_else(|| anyhow!("claim epoch exhausted"))?; - let claim_id = uuid::Uuid::new_v4().to_string(); - let attempt_id = uuid::Uuid::new_v4().to_string(); - let recovery_id = uuid::Uuid::new_v4().to_string(); - let receipt = WorkspaceCoverageRecoveryReceipt { - schema_version: RECOVERY_SCHEMA.into(), - recovery_id: recovery_id.clone(), - old_claim_id: old_claim.claim_id.clone(), - old_attempt_id: old_attempt.attempt_id.clone(), - old_claim_epoch: old_claim.claim_epoch, - termination_id: termination.termination_id.clone(), - termination_envelope_digest: termination_digest.clone(), - replacement_launch_id: replacement_launch.launch_id.clone(), - replacement_launch_envelope_digest: replacement_launch_digest, - ready_heartbeat_id: ready.heartbeat_id.clone(), - ready_heartbeat_envelope_digest: ready_digest, - new_claim_id: claim_id.clone(), - new_attempt_id: attempt_id.clone(), - new_claim_epoch: claim_epoch, - recovered_at_utc: ready.observed_at_utc.clone(), - old_launch_id: old_launch.launch_id.clone(), - }; - validate_recovery_receipt(&receipt)?; - let receipt_env = envelope(RECOVERY_TYPE, &recovery_id, &receipt)?; - let receipt_digest = cultcache_envelope_digest(&receipt_env); - - let completed_at = termination.observed_at_utc.clone(); - let mut failed_claim = old_claim.clone(); - failed_claim.schema_version = CLAIM_SCHEMA_V2.into(); - failed_claim.status = "failed".into(); - failed_claim.termination_evidence_id = Some(termination.termination_id.clone()); - failed_claim.termination_evidence_digest = Some(termination_digest.clone()); - failed_claim.recovery_receipt_id = Some(recovery_id.clone()); - failed_claim.recovery_receipt_digest = Some(receipt_digest.clone()); - let mut failed_attempt = old_attempt.clone(); - failed_attempt.schema_version = ATTEMPT_SCHEMA_V2.into(); - failed_attempt.status = "failed".into(); - failed_attempt.completed_at = Some(completed_at.clone()); - failed_attempt.error = Some("executor process terminated; lease recovered".into()); - failed_attempt.termination_evidence_id = Some(termination.termination_id.clone()); - failed_attempt.termination_evidence_digest = Some(termination_digest); - failed_attempt.recovery_receipt_id = Some(recovery_id.clone()); - failed_attempt.recovery_receipt_digest = Some(receipt_digest.clone()); - validate_claim_attempt_link(&failed_claim, &failed_attempt)?; - - let claim = WorkspaceCoverageProjectionClaim { - schema_version: CLAIM_SCHEMA_V3.into(), - claim_id: claim_id.clone(), - claim_epoch, - plan_id: plan.plan_id.clone(), - attempt_id: attempt_id.clone(), - obligation_id: obligation.obligation_id.clone(), - body_observation_id: old_claim.body_observation_id.clone(), - body_generation: old_claim.body_generation, - manifest_root_sha256: old_claim.manifest_root_sha256.clone(), - status: "running".into(), - executor_id: replacement_launch.provider_daemon_id.clone(), - executor_incarnation: replacement_launch.provider_incarnation_id.clone(), - managed_process_launch_id: replacement_launch.launch_id.clone(), - termination_evidence_id: None, - termination_evidence_digest: None, - recovery_receipt_id: Some(recovery_id.clone()), - recovery_receipt_digest: Some(receipt_digest.clone()), - }; - let attempt = WorkspaceCoverageProjectionAttempt { - schema_version: ATTEMPT_SCHEMA_V3.into(), - attempt_id: attempt_id.clone(), - claim_id, - claim_epoch, - plan_id: plan.plan_id.clone(), - status: "running".into(), - started_at: ready.observed_at_utc.clone(), - completed_at: None, - error: None, - executor_id: replacement_launch.provider_daemon_id.clone(), - executor_incarnation: replacement_launch.provider_incarnation_id.clone(), - managed_process_launch_id: replacement_launch.launch_id.clone(), - termination_evidence_id: None, - termination_evidence_digest: None, - recovery_receipt_id: Some(recovery_id.clone()), - recovery_receipt_digest: Some(receipt_digest), - }; - validate_claim_attempt_link(&claim, &attempt)?; - let mut expected = Vec::new(); - if let Some(head) = &prior_head { - expected.push(head.clone()); - } - expected.extend([claim_env.clone(), attempt_env.clone()]); - let mut replacements = Vec::new(); - if let Some(head) = &prior_head { - replacements.push(head.clone()); - } - let history_key = format!("history/{}", old_claim.claim_id); - if find(&opening, CLAIM_TYPE, &history_key).is_some() { - bail!("workspace coverage recovery claim history identity already exists"); - } - if find(&opening, RECOVERY_TYPE, &recovery_id).is_some() { - bail!("workspace coverage recovery receipt identity already exists"); - } - replacements.extend([ - receipt_env, - envelope(CLAIM_TYPE, &history_key, &failed_claim)?, - envelope(ATTEMPT_TYPE, &failed_attempt.attempt_id, &failed_attempt)?, - envelope(CLAIM_TYPE, &claim_key, &claim)?, - envelope(ATTEMPT_TYPE, &attempt.attempt_id, &attempt)?, - ]); - if !coverage - .store - .compare_and_swap_batch(&expected, replacements)? - { - bail!("workspace coverage recovery lost exact coverage-store plan/claim/attempt CAS"); - } - let closing_body = SingleFileMessagePackBackingStore::new(&body_store).pull_all()?; - for expected in body_authority { - if find(&closing_body, &expected.r#type, &expected.key) != Some(&expected) { - bail!("repository Body changed during workspace coverage recovery"); - } - } - Ok(WorkspaceCoverageRecoveryOutcome { - claim_id: claim.claim_id, - claim_epoch: claim.claim_epoch, - managed_process_launch_id: claim.managed_process_launch_id, - executor_incarnation: claim.executor_incarnation, - recovery_receipt_id: recovery_id, - recovery_receipt_digest: claim - .recovery_receipt_digest - .ok_or_else(|| anyhow!("recovered claim lost recovery receipt digest"))?, - }) -} - -fn validate_current_projection( - opening: &[CultCacheEnvelope], - prepared: &PreparedWorkspaceCoverageProjection, -) -> Result> { - let Some(head_env) = find(opening, HEAD_TYPE, HEAD_KEY) else { - return Ok(None); - }; - let head: WorkspaceCoverageHead = decode(head_env)?; - let obligation_env = find( - opening, - "gamecult.epiphany.workspace_coverage_obligation", - &head.obligation_id, - ) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing obligation"))?; - let plan_env = find( - opening, - "gamecult.epiphany.workspace_coverage_projection_plan", - &head.plan_id, - ) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing plan"))?; - let receipt_env = find(opening, RECEIPT_TYPE, &head.receipt_id) - .ok_or_else(|| anyhow!("current workspace coverage head names a missing receipt"))?; - let obligation: WorkspaceCoverageObligation = decode(obligation_env)?; - let plan: WorkspaceCoverageProjectionPlan = decode(plan_env)?; - let receipt: WorkspaceCoverageReceipt = decode(receipt_env)?; - validate_workspace_coverage_head(&obligation, &plan, &receipt, &head)?; - if obligation == prepared.obligation && plan == prepared.plan { - Ok(Some(receipt)) - } else { - Ok(None) - } -} - -pub(crate) fn fail_workspace_coverage_projection( - acquisition: &WorkspaceCoverageAcquisition, - error: &str, -) -> Result<()> { - if error.trim().is_empty() { - bail!("projection failure requires an error"); - } - let opening = acquisition.coverage_store.pull_all()?; - let claim_env = find(&opening, CLAIM_TYPE, &acquisition.claim_key) - .ok_or_else(|| anyhow!("running claim missing"))?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &acquisition.attempt.attempt_id) - .ok_or_else(|| anyhow!("running attempt missing"))?; - let claim: WorkspaceCoverageProjectionClaim = decode(claim_env)?; - let attempt: WorkspaceCoverageProjectionAttempt = decode(attempt_env)?; - let obligation_env = find( - &opening, - "gamecult.epiphany.workspace_coverage_obligation", - &acquisition.obligation.obligation_id, - ) - .ok_or_else(|| anyhow!("persisted projection obligation missing"))?; - let plan_env = find( - &opening, - "gamecult.epiphany.workspace_coverage_projection_plan", - &acquisition.plan.plan_id, - ) - .ok_or_else(|| anyhow!("persisted projection plan missing"))?; - if decode::(obligation_env)? != acquisition.obligation - || decode::(plan_env)? != acquisition.plan - { - bail!("projection failure refuses substituted obligation or plan"); - } - if claim != acquisition.claim || attempt != acquisition.attempt || claim.status != "running" { - bail!("projection failure refuses substituted claim or attempt"); - } - let mut failed_claim = claim.clone(); - failed_claim.status = "failed".into(); - let mut failed_attempt = attempt.clone(); - failed_attempt.status = "failed".into(); - failed_attempt.completed_at = Some(chrono::Utc::now().to_rfc3339()); - failed_attempt.error = Some(error.into()); - let expected = vec![ - obligation_env.clone(), - plan_env.clone(), - claim_env.clone(), - attempt_env.clone(), - ]; - let replacements = vec![ - obligation_env.clone(), - plan_env.clone(), - envelope(CLAIM_TYPE, &acquisition.claim_key, &failed_claim)?, - envelope(ATTEMPT_TYPE, &failed_attempt.attempt_id, &failed_attempt)?, - ]; - if !acquisition - .coverage_store - .compare_and_swap_batch(&expected, replacements)? - { - bail!("projection failure lost exact claim/attempt CAS"); - } - Ok(()) -} - -pub(crate) fn execute_workspace_coverage_projection( - acquisition: &WorkspaceCoverageAcquisition, - prepared: &PreparedWorkspaceCoverageProjection, - embedder: &OllamaEmbedder, - port: &mut impl WorkspaceCoverageProjectionPort, - authority: &WorkspaceCoverageProjectionExecutionAuthority<'_>, -) -> Result { - let result = (|| { - if prepared.body_store != acquisition.body_store - || prepared.obligation != acquisition.obligation - || prepared.plan != acquisition.plan - { - bail!("execution refuses a prepared projection other than the acquired projection"); - } - execute_batched_and_commit(acquisition, prepared, embedder, port, authority) - })(); - terminalize_execution_result(acquisition, result) -} - -fn execute_batched_and_commit( - acquisition: &WorkspaceCoverageAcquisition, - prepared: &PreparedWorkspaceCoverageProjection, - embedder: &OllamaEmbedder, - port: &mut impl WorkspaceCoverageProjectionPort, - authority: &WorkspaceCoverageProjectionExecutionAuthority<'_>, -) -> Result { - if authority.operation_timeout_ms == 0 { - bail!("workspace coverage execution authority requires a positive operation timeout"); - } - let planned = &acquisition.plan.planned_points; - if prepared.points.len() != planned.len() { - bail!("prepared projection does not equal the sealed plan point count"); - } - for (ordinal, (prepared_point, planned_point)) in - prepared.points.iter().zip(planned).enumerate() - { - if prepared_point.point_id != planned_point.point_id - || format!("{:x}", Sha256::digest(prepared_point.text.as_bytes())) - != planned_point.chunk_sha256 - { - bail!("prepared projection disagrees with sealed plan ordinal {ordinal}"); - } - } - let collection_name = workspace_coverage_execution_collection( - &acquisition.plan.plan_id, - &acquisition.claim.claim_id, - acquisition.claim.claim_epoch, - )?; - port.ensure_exact_collection( - &collection_name, - &collection_compatibility(&acquisition.plan), - )?; - - let checkpoint_chain = load_authenticated_checkpoint_chain( - &acquisition.body_store, - &authority.coverage_authority.store, - authority.local_verse_store, - authority.trusted_host, - &acquisition.claim.claim_id, - acquisition.claim.claim_epoch, - )?; - let mut next_ordinal = if let Some(current) = checkpoint_chain.last() { - for checkpoint in &checkpoint_chain { - authenticate_checkpoint_readback(&collection_name, &checkpoint.checkpoint, port)?; - } - current.checkpoint.cumulative_point_count as usize - } else { - if let Some(existing) = load_latest_workspace_coverage_projection_progress( - &authority.coverage_authority.store, - &acquisition.claim.managed_process_launch_id, - &acquisition.claim.claim_id, - )? { - let existing = authenticate_workspace_coverage_projection_progress( - &authority.coverage_authority.store, - authority.local_verse_store, - authority.runtime_id, - &existing.progress_id, - authority.trusted_host, - )?; - if existing.sequence != 1 - || existing.completed_units != 0 - || existing.checkpoint_id.is_some() - || existing.plan_id != acquisition.plan.plan_id - || existing.attempt_id != acquisition.attempt.attempt_id - { - bail!("checkpoint-free restart found progress other than exact genesis"); - } - } else { - publish_workspace_coverage_progress_genesis( - &acquisition.body_store, - &authority.coverage_authority.store, - authority.local_verse_store, - authority.runtime_id, - authority.trusted_host, - authority.provider_signing_key, - authority.operation_timeout_ms, - )?; - } - 0 - }; - - while next_ordinal < planned.len() { - let end = (next_ordinal + WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS).min(planned.len()); - let texts = prepared.points[next_ordinal..end] - .iter() - .map(|point| point.text.clone()) - .collect::>(); - let vectors = embedder.embed_documents(&texts)?; - if vectors.len() != texts.len() { - bail!("embedding provider omitted sealed batch vectors"); - } - let mut points = Vec::with_capacity(end - next_ordinal); - let mut expected_point_bindings = Vec::with_capacity(end - next_ordinal); - for ((prepared_point, expected), vector) in prepared.points[next_ordinal..end] - .iter() - .zip(&planned[next_ordinal..end]) - .zip(vectors) - { - if vector.len() != acquisition.plan.vector_dimensions as usize - || vector.iter().any(|value| !value.is_finite()) - { - bail!("embedding provider returned an invalid sealed batch vector"); - } - let payload = payload_for(&acquisition.obligation, &acquisition.plan, expected); - expected_point_bindings.push(WorkspaceCoveragePointBinding { - point_id: expected.point_id.clone(), - payload_sha256: digest(&payload)?, - }); - points.push(SemanticPoint { - id: prepared_point.point_id.clone(), - vector, - payload, - }); - } - port.upsert_waited_batch(&collection_name, &points)?; - let ids = points - .iter() - .map(|point| point.id.clone()) - .collect::>(); - let observed = port.observe_exact_ids(&collection_name, &ids)?; - let stored_vector_bindings = authenticate_submitted_cosine_batch_readback( - &observed, - &expected_point_bindings, - &points, - acquisition.plan.vector_dimensions, - )?; - let admitted = admit_observed_workspace_coverage_batch( - &acquisition.body_store, - &authority.coverage_authority.store, - authority.local_verse_store, - authority.runtime_id, - authority.trusted_host, - authority.provider_signing_key, - ObservedWorkspaceCoverageBatchInput { - claim_id: acquisition.claim.claim_id.clone(), - attempt_id: acquisition.attempt.attempt_id.clone(), - plan_id: acquisition.plan.plan_id.clone(), - first_plan_ordinal: next_ordinal as u64, - point_bindings: expected_point_bindings, - vector_bindings: stored_vector_bindings, - }, - )?; - publish_workspace_coverage_advancement_sight( - authority.local_verse_store, - authority.runtime_store, - authority.coverage_authority, - authority.runtime_id, - &acquisition.claim.managed_process_launch_id, - authority.trusted_host, - authority.provider_signing_key, - chrono::Utc::now(), - chrono::Duration::seconds(1), - )?; - debug_assert_eq!(admitted.checkpoint.claim_id, acquisition.claim.claim_id); - next_ordinal = end; - } - - let final_chain = load_authenticated_checkpoint_chain( - &acquisition.body_store, - &authority.coverage_authority.store, - authority.local_verse_store, - authority.trusted_host, - &acquisition.claim.claim_id, - acquisition.claim.claim_epoch, - )?; - let observed = observe_final_projection_against_authenticated_checkpoint_chain( - &acquisition.obligation, - &acquisition.plan, - &collection_name, - port.observe_all(&collection_name)?, - &final_chain, - )?; - let receipt = commit_workspace_coverage_success(acquisition, observed)?; - publish_workspace_coverage_terminal_sight( - authority.local_verse_store, - authority.runtime_store, - authority.coverage_authority, - authority.runtime_id, - &acquisition.claim.managed_process_launch_id, - authority.trusted_host, - authority.provider_signing_key, - chrono::Utc::now(), - )?; - Ok(receipt) -} - -fn authenticate_checkpoint_readback( - collection_name: &str, - checkpoint: &crate::workspace_coverage_projection_batch_checkpoint::WorkspaceCoverageProjectionBatchCheckpointEntry, - port: &mut impl WorkspaceCoverageProjectionPort, -) -> Result<()> { - if checkpoint.collection_name != collection_name { - bail!("checkpoint collection disagrees with the sealed execution collection"); - } - let observed = port.observe_exact_ids(collection_name, &checkpoint.point_ids)?; - authenticate_batch_readback( - &observed, - &checkpoint.point_bindings, - &checkpoint.vector_bindings, - checkpoint.vector_dimensions, - ) -} - -/// Authenticates Qdrant's documented Cosine-storage transformation and returns -/// bindings for the exact stored representation. Qdrant normalizes vectors on -/// upload for Cosine collections, so the submitted byte digest is not a valid -/// persistence invariant. Direction and unit norm prove the transformation; -/// the returned digest seals the stored bytes for checkpoint/restart proof. -fn authenticate_submitted_cosine_batch_readback( - observed: &[SemanticStoredPoint], - expected_points: &[WorkspaceCoveragePointBinding], - submitted: &[SemanticPoint], - vector_dimensions: u32, -) -> Result> { - if observed.len() != expected_points.len() || observed.len() != submitted.len() { - bail!("exact cosine batch readback count disagrees with submitted bindings"); - } - let mut observed = observed.iter().collect::>(); - let mut sorted_expected_points = expected_points.iter().collect::>(); - let mut submitted = submitted.iter().collect::>(); - observed.sort_by(|left, right| left.id.cmp(&right.id)); - sorted_expected_points.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - submitted.sort_by(|left, right| left.id.cmp(&right.id)); - let mut stored_by_id = std::collections::HashMap::with_capacity(observed.len()); - for ((point, expected_point), submitted) in observed - .into_iter() - .zip(sorted_expected_points) - .zip(submitted) - { - if point.id != expected_point.point_id || point.id != submitted.id { - bail!("exact cosine batch readback point identity disagrees with submission"); - } - let payload = point - .payload - .as_ref() - .ok_or_else(|| anyhow!("exact cosine batch readback omitted payload"))?; - if digest(payload)? != expected_point.payload_sha256 { - bail!( - "exact cosine batch readback payload digest disagrees for point {}", - point.id - ); - } - let vector = point - .vector - .as_ref() - .ok_or_else(|| anyhow!("exact cosine batch readback omitted vector"))?; - authenticate_cosine_storage_vector(&submitted.vector, vector, vector_dimensions) - .with_context(|| { - format!( - "Qdrant cosine transformation disagrees for point {}", - point.id - ) - })?; - if stored_by_id - .insert(point.id.clone(), digest(vector)?) - .is_some() - { - bail!("exact cosine batch readback duplicated a submitted point"); - } - } - expected_points - .iter() - .map(|point| { - Ok(WorkspaceCoverageVectorBinding { - point_id: point.point_id.clone(), - vector_sha256: stored_by_id.remove(&point.point_id).ok_or_else(|| { - anyhow!("exact cosine batch readback omitted a submitted point") - })?, - }) - }) - .collect() -} - -fn authenticate_cosine_storage_vector( - submitted: &[f32], - observed: &[f32], - vector_dimensions: u32, -) -> Result<()> { - if submitted.len() != vector_dimensions as usize || observed.len() != submitted.len() { - bail!("cosine vector dimensions disagree"); - } - if submitted - .iter() - .chain(observed) - .any(|value| !value.is_finite()) - { - bail!("cosine vector contains a non-finite component"); - } - let submitted_norm = submitted - .iter() - .map(|value| f64::from(*value) * f64::from(*value)) - .sum::() - .sqrt(); - let observed_norm = observed - .iter() - .map(|value| f64::from(*value) * f64::from(*value)) - .sum::() - .sqrt(); - if submitted_norm <= f64::EPSILON { - if observed.iter().any(|value| *value != 0.0) { - bail!("zero cosine vector changed during storage"); - } - return Ok(()); - } - if (observed_norm - 1.0).abs() > 1.0e-5 { - bail!("stored cosine vector is not unit normalized"); - } - for (submitted, observed) in submitted.iter().zip(observed) { - let normalized = f64::from(*submitted) / submitted_norm; - if (normalized - f64::from(*observed)).abs() > 2.0e-6 { - bail!("stored cosine vector changed direction beyond normalization tolerance"); - } - } - Ok(()) -} - -fn authenticate_batch_readback( - observed: &[SemanticStoredPoint], - expected_points: &[WorkspaceCoveragePointBinding], - expected_vectors: &[WorkspaceCoverageVectorBinding], - vector_dimensions: u32, -) -> Result<()> { - if observed.len() != expected_points.len() || observed.len() != expected_vectors.len() { - bail!("exact batch readback count disagrees with submitted bindings"); - } - // Qdrant's retrieve response is a set; it does not promise to preserve the - // request order. Authenticate the exact set by point identity instead of - // letting transport ordering impersonate a payload/vector substitution. - let mut observed = observed.iter().collect::>(); - let mut expected_points = expected_points.iter().collect::>(); - let mut expected_vectors = expected_vectors.iter().collect::>(); - observed.sort_by(|left, right| left.id.cmp(&right.id)); - expected_points.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - expected_vectors.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - for ((point, expected_point), expected_vector) in observed - .into_iter() - .zip(expected_points) - .zip(expected_vectors) - { - let payload = point - .payload - .as_ref() - .ok_or_else(|| anyhow!("exact batch readback omitted payload"))?; - let vector = point - .vector - .as_ref() - .ok_or_else(|| anyhow!("exact batch readback omitted vector"))?; - if point.id != expected_point.point_id || point.id != expected_vector.point_id { - bail!( - "exact batch readback point identity disagrees with submitted bindings: observed={}, payload_binding={}, vector_binding={}", - point.id, - expected_point.point_id, - expected_vector.point_id - ); - } - let observed_payload_sha256 = digest(payload)?; - if observed_payload_sha256 != expected_point.payload_sha256 { - bail!( - "exact batch readback payload digest disagrees for point {}: observed={}, expected={}", - point.id, - observed_payload_sha256, - expected_point.payload_sha256 - ); - } - if vector.len() != vector_dimensions as usize { - bail!( - "exact batch readback vector dimensions disagree for point {}: observed={}, expected={}", - point.id, - vector.len(), - vector_dimensions - ); - } - if vector.iter().any(|value| !value.is_finite()) { - bail!( - "exact batch readback vector is non-finite for point {}", - point.id - ); - } - let observed_vector_sha256 = digest(vector)?; - if observed_vector_sha256 != expected_vector.vector_sha256 { - bail!( - "exact batch readback vector digest disagrees for point {}: observed={}, expected={}", - point.id, - observed_vector_sha256, - expected_vector.vector_sha256 - ); - } - } - Ok(()) -} - -#[cfg(test)] -fn sealed_batch_ranges(point_count: usize) -> Vec> { - (0..point_count) - .step_by(WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS) - .map(|start| start..(start + WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS).min(point_count)) - .collect() -} - -#[cfg(test)] -fn execute_preembedded_workspace_coverage_projection( - acquisition: &WorkspaceCoverageAcquisition, - inputs: Vec, - port: &mut impl WorkspaceCoverageProjectionPort, -) -> Result { - let result = execute_and_commit(acquisition, inputs, port); - terminalize_execution_result(acquisition, result) -} - -fn terminalize_execution_result( - acquisition: &WorkspaceCoverageAcquisition, - result: Result, -) -> Result { - match result { - Ok(receipt) => Ok(receipt), - Err(error) => { - let message = format!("{error:#}"); - if let Err(terminal_error) = fail_workspace_coverage_projection(acquisition, &message) { - bail!( - "projection failed ({message}) and failure terminalization failed: {terminal_error:#}" - ); - } - Err(error) - } - } -} - -#[cfg(test)] -fn execute_and_commit( - acquisition: &WorkspaceCoverageAcquisition, - mut inputs: Vec, - port: &mut impl WorkspaceCoverageProjectionPort, -) -> Result { - inputs.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - let mut planned = acquisition.plan.planned_points.clone(); - planned.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - if inputs.len() != planned.len() { - bail!("projection inputs do not equal the sealed plan point count"); - } - let mut points = Vec::with_capacity(planned.len()); - let mut submitted_vector_bindings = Vec::with_capacity(planned.len()); - for (input, expected) in inputs.into_iter().zip(&planned) { - if input.point_id != expected.point_id - || input.vector.len() != acquisition.plan.vector_dimensions as usize - || input.vector.iter().any(|value| !value.is_finite()) - || format!("{:x}", Sha256::digest(input.text.as_bytes())) != expected.chunk_sha256 - { - bail!("projection input does not match its sealed point descriptor"); - } - submitted_vector_bindings.push(WorkspaceCoverageVectorBinding { - point_id: expected.point_id.clone(), - vector_sha256: digest(&input.vector)?, - }); - points.push(SemanticPoint { - id: expected.point_id.clone(), - vector: input.vector, - payload: payload_for(&acquisition.obligation, &acquisition.plan, expected), - }); - } - let collection_name = workspace_coverage_execution_collection( - &acquisition.plan.plan_id, - &acquisition.claim.claim_id, - acquisition.claim.claim_epoch, - )?; - let compatibility = collection_compatibility(&acquisition.plan); - port.ensure_exact_collection(&collection_name, &compatibility)?; - if !points.is_empty() { - port.upsert_waited_batch(&collection_name, &points)?; - } - let observed = observe_exact_bindings( - acquisition, - &collection_name, - port.observe_all(&collection_name)?, - &submitted_vector_bindings, - )?; - commit_workspace_coverage_success(acquisition, observed) -} - -#[cfg(test)] -fn observe_exact_bindings( - acquisition: &WorkspaceCoverageAcquisition, - collection_name: &str, - observed: Vec>, - submitted_vector_bindings: &[WorkspaceCoverageVectorBinding], -) -> Result { - let binding = observe_sealed_bindings( - &acquisition.obligation, - &acquisition.plan, - collection_name, - observed, - Some(submitted_vector_bindings), - )?; - Ok(binding) -} - -pub(crate) fn observe_final_projection_against_authenticated_checkpoint_chain( - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, - collection_name: &str, - observed: Vec>, - chain: &[WorkspaceCoverageProjectionBatchCheckpointAdmission], -) -> Result { - let mut expected_points = Vec::new(); - let mut expected_vectors = Vec::new(); - let mut expected_ordinal = 0_u64; - for admission in chain { - let checkpoint = &admission.checkpoint; - if checkpoint.obligation_id != obligation.obligation_id - || checkpoint.plan_id != plan.plan_id - || checkpoint.first_plan_ordinal != expected_ordinal - || checkpoint.point_bindings.len() != checkpoint.vector_bindings.len() - { - bail!("authenticated checkpoint chain disagrees with final sealed projection"); - } - expected_points.extend(checkpoint.point_bindings.iter().cloned()); - expected_vectors.extend(checkpoint.vector_bindings.iter().cloned()); - expected_ordinal = checkpoint.cumulative_point_count; - } - if expected_ordinal != plan.expected_point_count - || expected_points.len() as u64 != plan.expected_point_count - || expected_vectors.len() != expected_points.len() - { - bail!("authenticated checkpoint chain does not cover the complete sealed plan"); - } - for ((planned, point), vector) in plan - .planned_points - .iter() - .zip(&expected_points) - .zip(&expected_vectors) - { - if point.point_id != planned.point_id - || vector.point_id != planned.point_id - || point.payload_sha256 != digest(&payload_for(obligation, plan, planned))? - { - bail!("authenticated checkpoint chain order or payload binding is invalid"); - } - } - let ordered = authenticate_final_observation_against_checkpoint_bindings( - observed, - &expected_points, - &expected_vectors, - )?; - observe_sealed_bindings( - obligation, - plan, - collection_name, - ordered, - Some(&expected_vectors), - ) -} - -fn authenticate_final_observation_against_checkpoint_bindings( - observed: Vec>, - expected_points: &[WorkspaceCoveragePointBinding], - expected_vectors: &[WorkspaceCoverageVectorBinding], -) -> Result>> { - let mut observed_by_id = std::collections::HashMap::with_capacity(observed.len()); - for point in observed { - let point_id = point.id.clone(); - if observed_by_id.insert(point_id.clone(), point).is_some() { - bail!("final Qdrant observation duplicated checkpointed point {point_id}"); - } - } - if observed_by_id.len() != expected_points.len() { - bail!("final Qdrant observation cardinality disagrees with authenticated checkpoint chain"); - } - let mut ordered = Vec::with_capacity(expected_points.len()); - for (point, vector) in expected_points.iter().zip(expected_vectors) { - let observed = observed_by_id - .remove(&point.point_id) - .ok_or_else(|| anyhow!("final Qdrant observation omitted a checkpointed point"))?; - let payload = observed - .payload - .as_ref() - .ok_or_else(|| anyhow!("final Qdrant observation omitted checkpointed payload"))?; - let observed_vector = observed - .vector - .as_ref() - .ok_or_else(|| anyhow!("final Qdrant observation omitted checkpointed vector"))?; - if digest(payload)? != point.payload_sha256 - || digest(observed_vector)? != vector.vector_sha256 - { - bail!("final Qdrant payload/vector disagrees with authenticated checkpoint evidence"); - } - ordered.push(observed); - } - if !observed_by_id.is_empty() { - bail!("final Qdrant observation contains uncheckpointed points"); - } - Ok(ordered) -} - -fn observe_sealed_bindings( - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, - collection_name: &str, - observed: Vec>, - expected_vector_bindings: Option<&[WorkspaceCoverageVectorBinding]>, -) -> Result { - let mut bindings = Vec::with_capacity(observed.len()); - let mut vector_bindings = Vec::with_capacity(observed.len()); - for point in observed { - let payload = point - .payload - .ok_or_else(|| anyhow!("observed workspace point omitted payload"))?; - bindings.push(WorkspaceCoveragePointBinding { - point_id: point.id.clone(), - payload_sha256: digest(&payload)?, - }); - let vector = point - .vector - .ok_or_else(|| anyhow!("observed workspace point omitted vector"))?; - if vector.len() != plan.vector_dimensions as usize - || vector.iter().any(|value| !value.is_finite()) - { - bail!("observed workspace point has an invalid vector"); - } - vector_bindings.push(WorkspaceCoverageVectorBinding { - point_id: point.id, - vector_sha256: digest(&vector)?, - }); - } - bindings.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - if bindings - .windows(2) - .any(|pair| pair[0].point_id == pair[1].point_id) - { - bail!("observed workspace collection contains duplicate point IDs"); - } - if bindings != plan.point_bindings { - bail!("observed workspace point bindings do not equal the sealed plan"); - } - vector_bindings.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - if let Some(expected) = expected_vector_bindings { - if !same_vector_binding_set(&vector_bindings, expected) { - bail!("observed workspace vectors do not equal authenticated stored-vector evidence"); - } - } - // Payload hashes bind the exact obligation as well as the sealed plan. - // Recompute one expected payload per point rather than trusting Qdrant's - // typed decoding to establish semantic equality. - for point in &plan.planned_points { - let expected = payload_for(obligation, plan, point); - let expected_binding = WorkspaceCoveragePointBinding { - point_id: point.point_id.clone(), - payload_sha256: digest(&expected)?, - }; - if !bindings.contains(&expected_binding) { - bail!("observed workspace payload does not equal its sealed obligation and plan"); - } - } - let ids = bindings - .iter() - .map(|binding| binding.point_id.clone()) - .collect::>(); - Ok(WorkspaceCoverageObservedBinding { - collection_name: collection_name.into(), - point_count: bindings.len() as u64, - point_set_sha256: digest(&ids)?, - point_binding_set_sha256: digest(&bindings)?, - vector_binding_set_sha256: digest(&vector_bindings)?, - }) -} - -fn same_vector_binding_set( - observed: &[WorkspaceCoverageVectorBinding], - expected: &[WorkspaceCoverageVectorBinding], -) -> bool { - let mut observed = observed.to_vec(); - let mut expected = expected.to_vec(); - observed.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - expected.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - observed == expected -} - -pub(crate) fn commit_workspace_coverage_success( - acquisition: &WorkspaceCoverageAcquisition, - observed: WorkspaceCoverageObservedBinding, -) -> Result { - if observed.point_count != acquisition.plan.expected_point_count - || observed.point_set_sha256 != acquisition.plan.expected_point_set_sha256 - || observed.point_binding_set_sha256 != acquisition.plan.point_binding_set_sha256 - { - bail!("observed binding proof is not the sealed plan"); - } - let body_opening = - SingleFileMessagePackBackingStore::new(&acquisition.body_store).pull_all()?; - let body_authority = exact_obligation_body_authority(&body_opening, &acquisition.obligation)?; - let opening = acquisition.coverage_store.pull_all()?; - let obligation_env = find( - &opening, - "gamecult.epiphany.workspace_coverage_obligation", - &acquisition.obligation.obligation_id, - ) - .ok_or_else(|| anyhow!("persisted projection obligation missing"))?; - let plan_env = find( - &opening, - "gamecult.epiphany.workspace_coverage_projection_plan", - &acquisition.plan.plan_id, - ) - .ok_or_else(|| anyhow!("persisted projection plan missing"))?; - let claim_env = find(&opening, CLAIM_TYPE, &acquisition.claim_key) - .ok_or_else(|| anyhow!("running claim missing"))?; - let attempt_env = find(&opening, ATTEMPT_TYPE, &acquisition.attempt.attempt_id) - .ok_or_else(|| anyhow!("running attempt missing"))?; - if decode::(obligation_env)? != acquisition.obligation - || decode::(plan_env)? != acquisition.plan - || decode::(claim_env)? != acquisition.claim - || decode::(attempt_env)? != acquisition.attempt - { - bail!("success refuses substituted obligation, plan, claim, or attempt"); - } - if find(&opening, HEAD_TYPE, HEAD_KEY) != acquisition.prior_head.as_ref() { - bail!("workspace coverage success lost its acquired prior head"); - } - let observed_at = chrono::Utc::now().to_rfc3339(); - let receipt_id = digest(&( - &acquisition.obligation.obligation_id, - &acquisition.plan.plan_id, - &observed.collection_name, - &observed.point_binding_set_sha256, - &observed.vector_binding_set_sha256, - &acquisition.claim.claim_id, - acquisition.claim.claim_epoch, - ))?; - let receipt = WorkspaceCoverageReceipt { - schema_version: WORKSPACE_COVERAGE_RECEIPT_SCHEMA_VERSION.into(), - receipt_id, - obligation_id: acquisition.obligation.obligation_id.clone(), - plan_id: acquisition.plan.plan_id.clone(), - collection_name: observed.collection_name, - embedding_provider_id: acquisition.plan.embedding_provider_id.clone(), - embedding_model: acquisition.plan.embedding_model.clone(), - vector_dimensions: acquisition.plan.vector_dimensions, - observed_point_count: observed.point_count, - observed_point_set_sha256: observed.point_set_sha256, - observed_at, - observation_method: "qdrant_scroll_exact_point_bindings".into(), - observed_point_binding_set_sha256: observed.point_binding_set_sha256, - claim_id: acquisition.claim.claim_id.clone(), - claim_epoch: acquisition.claim.claim_epoch, - observed_vector_binding_set_sha256: observed.vector_binding_set_sha256, - }; - let head = WorkspaceCoverageHead { - schema_version: WORKSPACE_COVERAGE_HEAD_SCHEMA_VERSION.into(), - workspace_id: acquisition.obligation.workspace_id.clone(), - obligation_id: acquisition.obligation.obligation_id.clone(), - plan_id: acquisition.plan.plan_id.clone(), - receipt_id: receipt.receipt_id.clone(), - body_observation_id: acquisition.obligation.body_observation_id.clone(), - body_generation: acquisition.obligation.body_generation, - manifest_root_sha256: acquisition.obligation.manifest_root_sha256.clone(), - claim_id: acquisition.claim.claim_id.clone(), - claim_epoch: acquisition.claim.claim_epoch, - }; - validate_workspace_coverage_head(&acquisition.obligation, &acquisition.plan, &receipt, &head)?; - let mut completed_claim = acquisition.claim.clone(); - completed_claim.status = "succeeded".into(); - let mut completed_attempt = acquisition.attempt.clone(); - completed_attempt.status = "succeeded".into(); - completed_attempt.completed_at = Some(chrono::Utc::now().to_rfc3339()); - let mut expected = Vec::new(); - expected.extend([ - obligation_env.clone(), - plan_env.clone(), - claim_env.clone(), - attempt_env.clone(), - ]); - if let Some(prior_head) = &acquisition.prior_head { - expected.push(prior_head.clone()); - } - let mut replacements = Vec::new(); - replacements.extend([ - obligation_env.clone(), - plan_env.clone(), - envelope(CLAIM_TYPE, &acquisition.claim_key, &completed_claim)?, - envelope( - ATTEMPT_TYPE, - &completed_attempt.attempt_id, - &completed_attempt, - )?, - envelope(RECEIPT_TYPE, &receipt.receipt_id, &receipt)?, - envelope(HEAD_TYPE, HEAD_KEY, &head)?, - ]); - if !acquisition - .coverage_store - .compare_and_swap_batch(&expected, replacements)? - { - bail!("workspace coverage success lost exact coverage-store plan/claim CAS"); - } - let closing_body = - SingleFileMessagePackBackingStore::new(&acquisition.body_store).pull_all()?; - for expected in body_authority { - if find(&closing_body, &expected.r#type, &expected.key) != Some(&expected) { - bail!("repository Body changed during workspace coverage terminal commit"); - } - } - Ok(receipt) -} - -pub(crate) fn payload_for( - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, - point: &crate::WorkspaceCoveragePlannedPoint, -) -> WorkspaceCoveragePointPayload { - WorkspaceCoveragePointPayload { - obligation_id: obligation.obligation_id.clone(), - projection_schema_version: plan.projection_schema_version.clone(), - chunker_id: plan.chunker_id.clone(), - body_path: point.body_path.clone(), - source_raw_sha256: point.source_raw_sha256.clone(), - source_raw_byte_length: point.source_raw_byte_length, - chunk_index: point.chunk_index, - byte_start: point.byte_start, - byte_end: point.byte_end, - chunk_sha256: point.chunk_sha256.clone(), - } -} - -pub(crate) fn exact_obligation_body_authority( - opening: &[CultCacheEnvelope], - obligation: &WorkspaceCoverageObligation, -) -> Result> { - let head_env = find(opening, BODY_HEAD_TYPE, BODY_HEAD_KEY) - .ok_or_else(|| anyhow!("current Body head missing"))?; - let head: RepositoryBodyHead = decode(head_env)?; - if head.workspace_id != obligation.workspace_id - || head.generation != obligation.body_generation - || head.observation_id != obligation.body_observation_id - || head.manifest_root_sha256 != obligation.manifest_root_sha256 - { - bail!("workspace coverage success requires its exact current Body authority"); - } - [ - (BODY_BINDING_TYPE, BODY_BINDING_KEY), - (BODY_HEAD_TYPE, BODY_HEAD_KEY), - ( - BODY_OBSERVATION_TYPE, - obligation.body_observation_id.as_str(), - ), - (BODY_MANIFEST_TYPE, obligation.manifest_root_sha256.as_str()), - ] - .into_iter() - .map(|(ty, key)| { - find(opening, ty, key) - .cloned() - .ok_or_else(|| anyhow!("Body authority envelope {ty}/{key} missing")) - }) - .collect() -} - -fn digest(value: &(impl Serialize + ?Sized)) -> Result { - Ok(format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(value)?) - )) -} - -fn preserve_or_insert_immutable( - opening: &[CultCacheEnvelope], - expected: &mut Vec, - replacements: &mut Vec, - proposed: CultCacheEnvelope, -) -> Result<()> { - if let Some(existing) = find(opening, &proposed.r#type, &proposed.key) { - let mut comparable = proposed; - comparable.stored_at = existing.stored_at.clone(); - if &comparable != existing { - bail!("immutable workspace coverage document identity collision"); - } - expected.push(existing.clone()); - replacements.push(existing.clone()); - } else { - replacements.push(proposed); - } - Ok(()) -} - -fn chunk_descriptors( - path: &str, - raw_sha256: &str, - bytes: &[u8], -) -> Result> { - let text = std::str::from_utf8(bytes) - .map_err(|_| anyhow!("named text chunker refuses non-UTF-8 bytes"))?; - let mut line_starts = vec![0usize]; - for (index, byte) in text.bytes().enumerate() { - if byte == b'\n' && index + 1 < bytes.len() { - line_starts.push(index + 1); - } - } - let mut result = Vec::new(); - let mut start = 0usize; - let mut chunk_index = 0u32; - while start < bytes.len() { - let start_line = line_starts.partition_point(|line_start| *line_start <= start) - 1; - let end_line = (start_line + CHUNK_LINES).min(line_starts.len()); - let line_bounded_end = if end_line == line_starts.len() { - bytes.len() - } else { - line_starts[end_line] - }; - let mut end = line_bounded_end.min(start.saturating_add(CHUNK_MAX_BYTES)); - while end > start && !text.is_char_boundary(end) { - end -= 1; - } - if end == start { - bail!("named text chunker could not advance at a UTF-8 boundary"); - } - result.push(WorkspaceCoverageChunkDescriptor { - body_path: path.into(), - source_raw_sha256: raw_sha256.into(), - source_raw_byte_length: bytes.len() as u64, - chunk_index, - byte_start: start as u64, - byte_end: end as u64, - chunk_sha256: format!("{:x}", Sha256::digest(&bytes[start..end])), - }); - if end == bytes.len() { - break; - } - start = if end == line_bounded_end { - let overlap_start = line_starts[end_line - CHUNK_OVERLAP_LINES]; - if overlap_start > start { - overlap_start - } else { - end - } - } else { - end - }; - chunk_index = chunk_index - .checked_add(1) - .ok_or_else(|| anyhow!("chunk index exhausted"))?; - } - Ok(result) -} - -fn exact_body_authority( - opening: &[CultCacheEnvelope], - basis: &RepositoryBodyObservationBasis, -) -> Result> { - let head_env = find(opening, BODY_HEAD_TYPE, BODY_HEAD_KEY) - .ok_or_else(|| anyhow!("current Body head missing"))?; - let head: RepositoryBodyHead = decode(head_env)?; - if head.workspace_id != basis.workspace_id - || head.generation != basis.generation - || head.observation_id != basis.observation_id - || head.manifest_root_sha256 != basis.manifest_root_sha256 - { - bail!("workspace coverage acquisition requires the exact current Body head"); - } - [ - (BODY_BINDING_TYPE, BODY_BINDING_KEY), - (BODY_HEAD_TYPE, BODY_HEAD_KEY), - (BODY_OBSERVATION_TYPE, basis.observation_id.as_str()), - (BODY_MANIFEST_TYPE, basis.manifest_root_sha256.as_str()), - ] - .into_iter() - .map(|(ty, key)| { - find(opening, ty, key) - .cloned() - .ok_or_else(|| anyhow!("Body authority envelope {ty}/{key} missing")) - }) - .collect() -} - -fn find<'a>( - entries: &'a [CultCacheEnvelope], - ty: &str, - key: &str, -) -> Option<&'a CultCacheEnvelope> { - entries - .iter() - .find(|entry| entry.r#type == ty && entry.key == key) -} -fn decode(value: &CultCacheEnvelope) -> Result { - Ok(rmp_serde::from_slice(&value.payload)?) -} -fn envelope(ty: &str, key: &str, value: &T) -> Result { - Ok(CultCacheEnvelope { - key: key.into(), - r#type: ty.into(), - payload: rmp_serde::to_vec(value)?, - stored_at: chrono::Utc::now().to_rfc3339(), - schema_id: Some(ty.into()), - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::process::Command; - - #[derive(Clone, Copy)] - enum Hostility { - Honest, - IncompatibleCollection, - WrongPayload, - Extra, - Missing, - Duplicate, - MissingVector, - WrongVector, - WrongVectorDimension, - NonFiniteVector, - } - - struct FakeProjectionPort { - hostility: Hostility, - points: Vec>, - upsert_calls: usize, - collection_present: bool, - collection_compatibility: Option, - } - - impl FakeProjectionPort { - fn new(hostility: Hostility) -> Self { - Self { - hostility, - points: Vec::new(), - upsert_calls: 0, - collection_present: true, - collection_compatibility: None, - } - } - } - - impl WorkspaceCoverageProjectionPort for FakeProjectionPort { - fn ensure_exact_collection( - &mut self, - _: &str, - compatibility: &CollectionCompatibility, - ) -> Result<()> { - if matches!(self.hostility, Hostility::IncompatibleCollection) { - bail!("incompatible preexisting collection metadata"); - } - self.collection_compatibility = Some(compatibility.clone()); - Ok(()) - } - fn upsert_waited_batch( - &mut self, - _: &str, - points: &[SemanticPoint], - ) -> Result<()> { - self.upsert_calls += 1; - for point in points { - let stored = SemanticStoredPoint { - id: point.id.clone(), - payload: Some(point.payload.clone()), - vector: Some(point.vector.clone()), - }; - if let Some(existing) = self.points.iter_mut().find(|item| item.id == point.id) { - *existing = stored; - } else { - self.points.push(stored); - } - } - Ok(()) - } - fn observe_exact_ids( - &mut self, - _: &str, - point_ids: &[String], - ) -> Result>> { - point_ids - .iter() - .map(|id| { - self.points - .iter() - .find(|point| &point.id == id) - .cloned() - .ok_or_else(|| anyhow!("requested exact point is absent")) - }) - .collect() - } - fn observe_all( - &mut self, - _: &str, - ) -> Result>> { - let mut points = self.points.clone(); - match self.hostility { - Hostility::Honest | Hostility::IncompatibleCollection => {} - Hostility::WrongPayload => points[0].payload.as_mut().unwrap().chunk_index += 1, - Hostility::Extra => points.push(SemanticStoredPoint { - id: uuid::Uuid::new_v4().to_string(), - payload: points[0].payload.clone(), - vector: points[0].vector.clone(), - }), - Hostility::Missing => { - points.pop(); - } - Hostility::Duplicate => points.push(points[0].clone()), - Hostility::MissingVector => points[0].vector = None, - Hostility::WrongVector => points[0].vector.as_mut().unwrap()[0] += 0.5, - Hostility::WrongVectorDimension => { - points[0].vector.as_mut().unwrap().pop(); - } - Hostility::NonFiniteVector => { - points[0].vector.as_mut().unwrap()[0] = f32::NAN; - } - } - Ok(points) - } - } - - impl WorkspaceCoverageEvidencePort for FakeProjectionPort { - fn authenticate_exact_collection( - &mut self, - _: &str, - expected: &CollectionCompatibility, - ) -> Result<()> { - if !self.collection_present || self.collection_compatibility.as_ref() != Some(expected) - { - bail!("live collection is absent or incompatible"); - } - Ok(()) - } - - fn observe_all_for_evidence( - &mut self, - collection: &str, - ) -> Result>> { - WorkspaceCoverageProjectionPort::observe_all(self, collection) - } - } - - #[test] - fn sealed_batch_ranges_preserve_plan_order_and_own_checkpoint_cadence() { - let total = WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS * 2 + 3; - let ranges = sealed_batch_ranges(total); - assert_eq!(WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS, 128); - assert_eq!( - ranges.len(), - total.div_ceil(WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS) - ); - assert!(ranges.iter().all(|range| range.len() - <= WORKSPACE_COVERAGE_CHECKPOINT_BATCH_POINTS - && range.len() <= QDRANT_POINT_BATCH_MAX)); - assert_eq!(ranges.last().unwrap().len(), 3); - assert_eq!( - ranges.into_iter().flatten().collect::>(), - (0..total).collect::>() - ); - } - - #[test] - fn stored_vector_evidence_comparison_is_order_independent_but_digest_exact() { - let first = WorkspaceCoverageVectorBinding { - point_id: "b".into(), - vector_sha256: "11".repeat(32), - }; - let second = WorkspaceCoverageVectorBinding { - point_id: "a".into(), - vector_sha256: "22".repeat(32), - }; - assert!(same_vector_binding_set( - &[first.clone(), second.clone()], - &[second.clone(), first.clone()] - )); - let mut changed = second.clone(); - changed.vector_sha256 = "33".repeat(32); - assert!(!same_vector_binding_set( - &[first.clone(), changed], - &[first, second] - )); - } - - #[test] - fn exact_batch_readback_rejects_vector_substitution() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let body = RepositoryBodyReadSession::open(&runtime, &basis)?; - let prepared = prepare_workspace_coverage_projection(&body, "provider", "model", 3)?; - let planned = prepared - .plan - .planned_points - .first() - .ok_or_else(|| anyhow!("fixture produced no planned points"))?; - let payload = payload_for(&prepared.obligation, &prepared.plan, planned); - let expected_vector = vec![0.25_f32; 3]; - let point_bindings = vec![WorkspaceCoveragePointBinding { - point_id: planned.point_id.clone(), - payload_sha256: digest(&payload)?, - }]; - let vector_bindings = vec![WorkspaceCoverageVectorBinding { - point_id: planned.point_id.clone(), - vector_sha256: digest(&expected_vector)?, - }]; - let observed = vec![SemanticStoredPoint { - id: planned.point_id.clone(), - payload: Some(payload), - vector: Some(vec![0.5_f32; 3]), - }]; - assert!( - authenticate_batch_readback(&observed, &point_bindings, &vector_bindings, 3).is_err() - ); - drop(repo); - Ok(()) - } - - #[test] - fn exact_batch_readback_authenticates_qdrant_set_independent_of_response_order() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let planned = acquisition - .plan - .planned_points - .first() - .ok_or_else(|| anyhow!("fixture produced no planned points"))?; - let payload_a = payload_for(&acquisition.obligation, &acquisition.plan, planned); - let mut payload_b = payload_a.clone(); - payload_b.chunk_index += 1; - let point_a = planned.point_id.clone(); - let point_b = uuid::Uuid::new_v4().to_string(); - let vector_a = vec![0.25_f32; 3]; - let vector_b = vec![0.5_f32; 3]; - let expected_points = vec![ - WorkspaceCoveragePointBinding { - point_id: point_a.clone(), - payload_sha256: digest(&payload_a)?, - }, - WorkspaceCoveragePointBinding { - point_id: point_b.clone(), - payload_sha256: digest(&payload_b)?, - }, - ]; - let expected_vectors = vec![ - WorkspaceCoverageVectorBinding { - point_id: point_a.clone(), - vector_sha256: digest(&vector_a)?, - }, - WorkspaceCoverageVectorBinding { - point_id: point_b.clone(), - vector_sha256: digest(&vector_b)?, - }, - ]; - let reversed = vec![ - SemanticStoredPoint { - id: point_b, - payload: Some(payload_b), - vector: Some(vector_b), - }, - SemanticStoredPoint { - id: point_a, - payload: Some(payload_a), - vector: Some(vector_a), - }, - ]; - - authenticate_batch_readback(&reversed, &expected_points, &expected_vectors, 3)?; - drop(repo); - Ok(()) - } - - #[test] - fn cosine_batch_readback_seals_qdrant_normalized_storage_not_submission_bytes() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let planned = acquisition - .plan - .planned_points - .first() - .ok_or_else(|| anyhow!("fixture produced no planned points"))?; - let payload = payload_for(&acquisition.obligation, &acquisition.plan, planned); - let mut payload_second = payload.clone(); - payload_second.chunk_index += 1; - let second_id = "00000000-0000-0000-0000-000000000001".to_string(); - let submitted_vector = vec![3.0_f32, 4.0, 0.0]; - let stored_vector = vec![0.6_f32, 0.8, 0.0]; - let submitted_second = vec![0.0_f32, 0.0, 5.0]; - let stored_second = vec![0.0_f32, 0.0, 1.0]; - let submitted = vec![ - SemanticPoint { - id: planned.point_id.clone(), - vector: submitted_vector.clone(), - payload: payload.clone(), - }, - SemanticPoint { - id: second_id.clone(), - vector: submitted_second, - payload: payload_second.clone(), - }, - ]; - let observed = vec![ - SemanticStoredPoint { - id: second_id.clone(), - payload: Some(payload_second.clone()), - vector: Some(stored_second.clone()), - }, - SemanticStoredPoint { - id: planned.point_id.clone(), - payload: Some(payload.clone()), - vector: Some(stored_vector.clone()), - }, - ]; - let point_bindings = vec![ - WorkspaceCoveragePointBinding { - point_id: planned.point_id.clone(), - payload_sha256: digest(&payload)?, - }, - WorkspaceCoveragePointBinding { - point_id: second_id.clone(), - payload_sha256: digest(&payload_second)?, - }, - ]; - - let bindings = authenticate_submitted_cosine_batch_readback( - &observed, - &point_bindings, - &submitted, - 3, - )?; - assert_eq!( - bindings - .iter() - .map(|binding| &binding.point_id) - .collect::>(), - vec![&planned.point_id, &second_id] - ); - assert_eq!(bindings[0].vector_sha256, digest(&stored_vector)?); - assert_ne!(bindings[0].vector_sha256, digest(&submitted_vector)?); - - let mut changed = observed; - changed[1].vector = Some(vec![0.8, 0.6, 0.0]); - assert!( - authenticate_submitted_cosine_batch_readback(&changed, &point_bindings, &submitted, 3,) - .is_err() - ); - drop(repo); - Ok(()) - } - - #[test] - fn final_checkpoint_proof_rejects_mutated_or_missing_earlier_point() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let planned = acquisition - .plan - .planned_points - .first() - .ok_or_else(|| anyhow!("fixture produced no planned points"))?; - let payload = payload_for(&acquisition.obligation, &acquisition.plan, planned); - let vector = vec![0.25_f32; 3]; - let point_bindings = vec![WorkspaceCoveragePointBinding { - point_id: planned.point_id.clone(), - payload_sha256: digest(&payload)?, - }]; - let vector_bindings = vec![WorkspaceCoverageVectorBinding { - point_id: planned.point_id.clone(), - vector_sha256: digest(&vector)?, - }]; - let observed = vec![SemanticStoredPoint { - id: planned.point_id.clone(), - payload: Some(payload), - vector: Some(vector), - }]; - authenticate_final_observation_against_checkpoint_bindings( - observed.clone(), - &point_bindings, - &vector_bindings, - )?; - let mut mutated = observed.clone(); - mutated[0].vector.as_mut().unwrap()[0] += 1.0; - assert!( - authenticate_final_observation_against_checkpoint_bindings( - mutated, - &point_bindings, - &vector_bindings, - ) - .is_err() - ); - assert!( - authenticate_final_observation_against_checkpoint_bindings( - Vec::new(), - &point_bindings, - &vector_bindings, - ) - .is_err() - ); - let mut duplicated = observed.clone(); - duplicated.push(observed[0].clone()); - assert!( - authenticate_final_observation_against_checkpoint_bindings( - duplicated, - &point_bindings, - &vector_bindings, - ) - .is_err() - ); - let mut substituted_duplicate = observed[0].clone(); - substituted_duplicate.vector.as_mut().unwrap()[0] += 1.0; - let mut duplicated = observed.clone(); - duplicated.push(substituted_duplicate); - assert!( - authenticate_final_observation_against_checkpoint_bindings( - duplicated, - &point_bindings, - &vector_bindings, - ) - .is_err() - ); - drop(repo); - Ok(()) - } - - struct AdvancingEvidencePort { - inner: FakeProjectionPort, - coverage_store: OwnedRedbMessagePackBackingStore, - claim_key: String, - } - - impl WorkspaceCoverageEvidencePort for AdvancingEvidencePort { - fn authenticate_exact_collection( - &mut self, - collection: &str, - expected: &CollectionCompatibility, - ) -> Result<()> { - self.inner - .authenticate_exact_collection(collection, expected) - } - - fn observe_all_for_evidence( - &mut self, - collection: &str, - ) -> Result>> { - let points = self.inner.observe_all_for_evidence(collection)?; - let opening = self.coverage_store.pull_all()?; - let current = find(&opening, CLAIM_TYPE, &self.claim_key) - .ok_or_else(|| anyhow!("test current claim disappeared"))? - .clone(); - let mut advanced: WorkspaceCoverageProjectionClaim = decode(¤t)?; - advanced.executor_id.push_str("-advanced"); - if !self.coverage_store.compare_and_swap_batch( - &[current], - vec![envelope(CLAIM_TYPE, &self.claim_key, &advanced)?], - )? { - bail!("test authority advance lost its CAS"); - } - Ok(points) - } - } - - #[derive(Default)] - struct FakeRetirementPort { - present: std::collections::BTreeMap, - retired: Vec, - } - - impl WorkspaceCoverageRetirementPort for FakeRetirementPort { - fn retire_exact( - &mut self, - collection: &str, - compatibility: &CollectionCompatibility, - ) -> Result<()> { - let Some(actual) = self.present.get(collection) else { - return Ok(()); - }; - if actual != compatibility { - bail!("incompatible same-name collection"); - } - self.present.remove(collection); - self.retired.push(collection.into()); - Ok(()) - } - } - - fn coverage_fixture() -> Result<( - tempfile::TempDir, - tempfile::TempDir, - PathBuf, - RepositoryBodyObservationBasis, - )> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("source.rs"), "fn one() {}\n")?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "retirement-runtime".into(), - display_name: "retirement".into(), - created_at: "2026-07-16T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "retirement-swarm", "2026-07-16T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "retirement-workspace")?; - let coverage = std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"); - crate::bind_runtime_workspace_coverage_store(&runtime, &coverage, "2026-07-16T00:00:02Z")?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - Ok((repo, state, runtime, basis)) - } - - #[test] - fn retirement_collects_failed_retry_but_preserves_running_attempt() -> Result<()> { - let (_repo, _state, runtime, basis) = coverage_fixture()?; - let (_, failed) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let failed_name = workspace_coverage_execution_collection( - &failed.plan.plan_id, - &failed.claim.claim_id, - failed.claim.claim_epoch, - )?; - fail_workspace_coverage_projection(&failed, "backend refused")?; - drop(failed); - let (_, running) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let candidates = workspace_coverage_retirement_candidates(&running.coverage_store)?; - assert_eq!( - candidates - .iter() - .map(|c| c.collection_name.as_str()) - .collect::>(), - vec![failed_name] - ); - assert!(!candidates.iter().any(|c| { - c.collection_name - == workspace_coverage_execution_collection( - &running.plan.plan_id, - &running.claim.claim_id, - running.claim.claim_epoch, - ) - .unwrap() - })); - Ok(()) - } - - #[test] - fn prior_success_retires_only_after_new_head_commits() -> Result<()> { - let (repo, _state, runtime, basis_a) = coverage_fixture()?; - let (_, acquired_a) = acquire_test(&runtime, &basis_a, "provider", "model", 3)?; - let receipt_a = execute_preembedded_workspace_coverage_projection( - &acquired_a, - projection_inputs(&acquired_a, repo.path())?, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - assert!(workspace_coverage_retirement_candidates(&acquired_a.coverage_store)?.is_empty()); - - std::fs::write(repo.path().join("source.rs"), "fn two() {}\n")?; - let basis_b = crate::observe_runtime_repository_body_basis(&runtime)?; - drop(acquired_a); - let (_, acquired_b) = acquire_test(&runtime, &basis_b, "provider", "model", 3)?; - assert!(workspace_coverage_retirement_candidates(&acquired_b.coverage_store)?.is_empty()); - execute_preembedded_workspace_coverage_projection( - &acquired_b, - projection_inputs(&acquired_b, repo.path())?, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - let candidates = workspace_coverage_retirement_candidates(&acquired_b.coverage_store)?; - assert_eq!(candidates.len(), 1); - assert_eq!(candidates[0].collection_name, receipt_a.collection_name); - Ok(()) - } - - #[test] - fn retirement_refuses_incompatible_collection_and_absence_is_idempotent() -> Result<()> { - let (_repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquired) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - fail_workspace_coverage_projection(&acquired, "failed")?; - let candidate = - workspace_coverage_retirement_candidates(&acquired.coverage_store)?.remove(0); - let mut port = FakeRetirementPort::default(); - let mut incompatible = candidate.compatibility.clone(); - incompatible.embedding_model.push_str("-alien"); - port.present - .insert(candidate.collection_name.clone(), incompatible); - drop(acquired); - let authority = crate::open_workspace_coverage_authority(&runtime)?; - assert!(retire_workspace_coverage_collections(&authority, &mut port).is_err()); - port.present.clear(); - assert_eq!( - retire_workspace_coverage_collections(&authority, &mut port)?, - 1 - ); - assert_eq!( - retire_workspace_coverage_collections(&authority, &mut port)?, - 1 - ); - assert!(port.retired.is_empty()); - Ok(()) - } - - fn projection_inputs( - acquisition: &WorkspaceCoverageAcquisition, - repo: &Path, - ) -> Result> { - acquisition - .plan - .planned_points - .iter() - .map(|point| { - let bytes = std::fs::read(repo.join(&point.body_path))?; - let text = std::str::from_utf8( - &bytes[point.byte_start as usize..point.byte_end as usize], - )? - .to_string(); - Ok(WorkspaceCoverageProjectionInput { - point_id: point.point_id.clone(), - text, - vector: vec![0.25; acquisition.plan.vector_dimensions as usize], - }) - }) - .collect() - } - - fn acquire_test( - runtime: &Path, - basis: &RepositoryBodyObservationBasis, - provider: &str, - model: &str, - dimensions: u32, - ) -> Result<( - PreparedWorkspaceCoverageProjection, - WorkspaceCoverageAcquisition, - )> { - let body = RepositoryBodyReadSession::open(runtime, basis)?; - let prepared = prepare_workspace_coverage_projection(&body, provider, model, dimensions)?; - let coverage = crate::open_workspace_coverage_authority(runtime)?; - acquire_test_with_store(prepared, &coverage.store) - } - - fn acquire_test_with_store( - prepared: PreparedWorkspaceCoverageProjection, - coverage_store: &OwnedRedbMessagePackBackingStore, - ) -> Result<( - PreparedWorkspaceCoverageProjection, - WorkspaceCoverageAcquisition, - )> { - let acquisition = match acquire_workspace_coverage_projection( - &prepared, - coverage_store, - "test-executor", - "test-incarnation", - "test-startup-receipt", - )? { - WorkspaceCoverageAcquireResult::Acquired(acquisition) => acquisition, - WorkspaceCoverageAcquireResult::Current(_) => { - bail!("test unexpectedly found a current projection") - } - WorkspaceCoverageAcquireResult::Contended => { - bail!("test unexpectedly found a contended projection") - } - }; - Ok((prepared, acquisition)) - } - - #[test] - fn live_coverage_evidence_requires_exact_rescroll_and_authority_chain() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let inputs = projection_inputs(&acquisition, repo.path())?; - let expected_claim_id = acquisition.claim.claim_id.clone(); - let mut projection = FakeProjectionPort::new(Hostility::Honest); - let receipt = execute_preembedded_workspace_coverage_projection( - &acquisition, - inputs, - &mut projection, - )?; - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( - WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, - )?; - - let evidence = observe_current_workspace_coverage_evidence_with_store( - &runtime, - &acquisition.coverage_store, - &basis, - &policy, - "provider", - "model", - 3, - &mut projection, - )? - .expect("live exact coverage evidence"); - assert_eq!(evidence.claim_id, expected_claim_id); - assert_eq!(evidence.receipt_id, receipt.receipt_id); - assert_eq!( - evidence.observed_vector_binding_set_sha256, - receipt.observed_vector_binding_set_sha256 - ); - assert!(evidence.head_envelope_digest.starts_with("sha256-")); - - let wrong_policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( - WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES - 1, - )?; - assert!( - observe_current_workspace_coverage_evidence_with_store( - &runtime, - &acquisition.coverage_store, - &basis, - &wrong_policy, - "provider", - "model", - 3, - &mut projection, - )? - .is_none() - ); - Ok(()) - } - - #[test] - fn stored_current_coverage_cannot_substitute_for_live_qdrant_evidence() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let inputs = projection_inputs(&acquisition, repo.path())?; - let mut projection = FakeProjectionPort::new(Hostility::Honest); - execute_preembedded_workspace_coverage_projection(&acquisition, inputs, &mut projection)?; - let terminal = authenticate_current_workspace_coverage_terminal_authority_with_store( - &runtime, - &acquisition.coverage_store, - )? - .expect("succeeded current receipt/head must own terminal health"); - assert_eq!(terminal.claim_id, acquisition.claim.claim_id); - assert_eq!(terminal.plan_id, acquisition.plan.plan_id); - assert!(matches!( - classify_current_workspace_coverage( - &runtime, - &acquisition.coverage_store, - &basis, - "provider", - "model", - 3, - )?, - WorkspaceCoverageCurrentState::Current(_) - )); - 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; - assert!( - observe_current_workspace_coverage_evidence_with_store( - &runtime, - &acquisition.coverage_store, - &basis, - &policy, - "provider", - "model", - 3, - &mut missing_live_collection, - ) - .is_err() - ); - - let mut wrong_compatibility = FakeProjectionPort { - hostility: Hostility::Honest, - points: projection.points.clone(), - upsert_calls: 0, - collection_present: true, - collection_compatibility: projection.collection_compatibility.clone(), - }; - wrong_compatibility - .collection_compatibility - .as_mut() - .expect("test collection compatibility") - .vector_size += 1; - assert!( - observe_current_workspace_coverage_evidence_with_store( - &runtime, - &acquisition.coverage_store, - &basis, - &policy, - "provider", - "model", - 3, - &mut wrong_compatibility, - ) - .is_err() - ); - - for hostility in [Hostility::WrongPayload, Hostility::WrongVector] { - let mut hostile = FakeProjectionPort { - hostility, - points: projection.points.clone(), - upsert_calls: 0, - collection_present: true, - collection_compatibility: projection.collection_compatibility.clone(), - }; - assert!( - observe_current_workspace_coverage_evidence_with_store( - &runtime, - &acquisition.coverage_store, - &basis, - &policy, - "provider", - "model", - 3, - &mut hostile, - ) - .is_err() - ); - } - Ok(()) - } - - #[test] - fn terminal_health_refuses_a_receipt_for_an_older_body() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let inputs = projection_inputs(&acquisition, repo.path())?; - execute_preembedded_workspace_coverage_projection( - &acquisition, - inputs, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - assert!( - authenticate_current_workspace_coverage_terminal_authority_with_store( - &runtime, - &acquisition.coverage_store, - )? - .is_some() - ); - std::fs::write(repo.path().join("source.rs"), "pub fn changed() {}\n")?; - crate::observe_runtime_repository_body_basis(&runtime)?; - assert!( - authenticate_current_workspace_coverage_terminal_authority_with_store( - &runtime, - &acquisition.coverage_store, - )? - .is_none() - ); - Ok(()) - } - - #[test] - fn sight_publication_refuses_body_movement_after_entry_construction() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let authority = crate::open_workspace_coverage_authority(&runtime)?; - crate::workspace_coverage_process_documents::validate_workspace_coverage_sight_closing_authority( - &runtime, - &authority, - &basis.workspace_id, - &basis.body_binding_sha256, - &basis.observation_id, - basis.generation, - &basis.manifest_root_sha256, - )?; - std::fs::write(repo.path().join("source.rs"), "pub fn moved() {}\n")?; - crate::observe_runtime_repository_body_basis(&runtime)?; - assert!(crate::workspace_coverage_process_documents::validate_workspace_coverage_sight_closing_authority( - &runtime, - &authority, - &basis.workspace_id, - &basis.body_binding_sha256, - &basis.observation_id, - basis.generation, - &basis.manifest_root_sha256, - ).is_err()); - Ok(()) - } - - #[test] - fn live_evidence_refuses_authority_advanced_during_qdrant_scroll() -> Result<()> { - let (repo, _state, runtime, basis) = coverage_fixture()?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let inputs = projection_inputs(&acquisition, repo.path())?; - let mut projection = FakeProjectionPort::new(Hostility::Honest); - execute_preembedded_workspace_coverage_projection(&acquisition, inputs, &mut projection)?; - let mut advancing = AdvancingEvidencePort { - inner: projection, - coverage_store: acquisition.coverage_store.clone(), - claim_key: acquisition.claim_key.clone(), - }; - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( - WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, - )?; - assert!( - observe_current_workspace_coverage_evidence_with_store( - &runtime, - &acquisition.coverage_store, - &basis, - &policy, - "provider", - "model", - 3, - &mut advancing, - )? - .is_none(), - "authority advanced during live scroll must request retry, not emit evidence" - ); - Ok(()) - } - - #[test] - fn named_chunker_preserves_utf8_boundaries_and_eight_line_overlap() -> Result<()> { - let text = (0..105) - .map(|index| format!("line {index} λ\n")) - .collect::(); - let chunks = chunk_descriptors("a", &"11".repeat(32), text.as_bytes())?; - assert_eq!(chunks.len(), 2); - let overlap = &text.as_bytes()[chunks[1].byte_start as usize..chunks[0].byte_end as usize]; - assert_eq!(overlap.iter().filter(|byte| **byte == b'\n').count(), 8); - assert!( - std::str::from_utf8( - &text.as_bytes()[chunks[0].byte_start as usize..chunks[0].byte_end as usize] - ) - .is_ok() - ); - assert!( - std::str::from_utf8( - &text.as_bytes()[chunks[1].byte_start as usize..chunks[1].byte_end as usize] - ) - .is_ok() - ); - assert_eq!(chunks[0].chunk_index, 0); - assert_eq!(chunks[1].chunk_index, 1); - assert!(chunk_descriptors("binary", &"22".repeat(32), &[0xff, 0xfe]).is_err()); - Ok(()) - } - - #[test] - fn named_chunker_bounds_pathological_long_lines_by_utf8_bytes() -> Result<()> { - let text = format!( - "{}λ{}\n", - "a".repeat(CHUNK_MAX_BYTES), - "b".repeat(CHUNK_MAX_BYTES) - ); - let chunks = chunk_descriptors("minified", &"33".repeat(32), text.as_bytes())?; - assert!(chunks.len() >= 3); - assert!(chunks.iter().all(|chunk| { - let start = chunk.byte_start as usize; - let end = chunk.byte_end as usize; - end > start - && end - start <= CHUNK_MAX_BYTES - && text.is_char_boundary(start) - && text.is_char_boundary(end) - })); - assert_eq!(chunks.first().unwrap().byte_start, 0); - assert_eq!(chunks.last().unwrap().byte_end, text.len() as u64); - for pair in chunks.windows(2) { - assert!(pair[1].byte_start <= pair[0].byte_end); - } - Ok(()) - } - - fn git(repo: &Path, args: &[&str]) -> Result<()> { - let output = Command::new("git") - .args(["-C", repo.to_str().unwrap()]) - .args(args) - .output()?; - if !output.status.success() { - bail!("git failed: {}", String::from_utf8_lossy(&output.stderr)); - } - Ok(()) - } - - #[test] - fn preparation_authenticates_body_store_constant_times_and_current_path_reads_no_files() - -> Result<()> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - for index in 0..12 { - std::fs::write( - repo.path().join(format!("source-{index}.rs")), - format!("fn f{index}() {{}}\n"), - )?; - } - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body_store = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "read-session-runtime".into(), - display_name: "read session".into(), - created_at: "2026-07-16T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "read-session-swarm", "2026-07-16T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body_store, &runtime, "read-session-workspace")?; - let coverage_store = std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"); - crate::bind_runtime_workspace_coverage_store( - &runtime, - &coverage_store, - "2026-07-16T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - - crate::repository_body_observer::reset_repository_body_read_counters(); - let body = RepositoryBodyReadSession::open(&runtime, &basis)?; - let prepared = prepare_workspace_coverage_projection(&body, "provider", "model", 3)?; - let (store_loads, file_reads) = - crate::repository_body_observer::repository_body_read_counters(); - assert_eq!(store_loads, 2, "Body store validation count changed"); - assert_eq!(file_reads, 12); - - let acquisition = match acquire_workspace_coverage_projection( - &prepared, - &crate::open_workspace_coverage_authority(&runtime)?.store, - "test-executor", - "test-incarnation", - "test-startup-receipt", - )? { - WorkspaceCoverageAcquireResult::Acquired(value) => value, - _ => bail!("initial projection was not acquired"), - }; - let inputs = projection_inputs(&acquisition, repo.path())?; - let receipt = execute_preembedded_workspace_coverage_projection( - &acquisition, - inputs, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - crate::repository_body_observer::reset_repository_body_read_counters(); - match classify_current_workspace_coverage( - &runtime, - &acquisition.coverage_store, - &basis, - "provider", - "model", - 3, - )? { - WorkspaceCoverageCurrentState::Current(current) => assert_eq!(current, receipt), - WorkspaceCoverageCurrentState::NeedsPreparation => { - bail!("exact projection was not current") - } - } - assert_eq!( - crate::repository_body_observer::repository_body_read_counters().1, - 0, - "current classification rematerialized Repository Body files" - ); - Ok(()) - } - - #[test] - fn acquisition_is_exclusive_and_failure_can_terminalize_after_body_advance() -> Result<()> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("source.rs"), "fn one() {}")?; - std::fs::write(repo.path().join("binary.dat"), [0xff, 0xfe, 0xfd])?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "projector-runtime".into(), - display_name: "projector test".into(), - created_at: "2026-07-15T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "projector-swarm", "2026-07-15T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "projector-workspace")?; - crate::bind_runtime_workspace_coverage_store( - &runtime, - std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"), - "2026-07-15T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, first) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - assert!(first.obligation.classifications.iter().any(|entry| { - entry.path == "binary.dat" - && entry.disposition - == crate::WorkspaceCoverageDisposition::ExcludeNonUtf8RegularFile - })); - assert_eq!(first.obligation.included_entry_count, 1); - assert!(matches!( - acquire_workspace_coverage_projection( - &prepare_workspace_coverage_projection( - &RepositoryBodyReadSession::open(&runtime, &basis)?, - "provider", - "model", - 3, - )?, - &first.coverage_store, - "other-executor", - "other-incarnation", - "other-startup-receipt", - )?, - WorkspaceCoverageAcquireResult::Contended - )); - fail_workspace_coverage_projection(&first, "expected test failure")?; - let second_prepared = prepare_workspace_coverage_projection( - &RepositoryBodyReadSession::open(&runtime, &basis)?, - "provider", - "model", - 3, - )?; - let (_, second) = acquire_test_with_store(second_prepared, &first.coverage_store)?; - assert_eq!(second.claim.claim_epoch, first.claim.claim_epoch + 1); - std::fs::write(repo.path().join("source.rs"), "fn two() {}")?; - let advanced = crate::observe_runtime_repository_body_basis(&runtime)?; - assert!(advanced.generation > basis.generation); - fail_workspace_coverage_projection(&second, "Body advanced during projection")?; - let entries = second.coverage_store.pull_all()?; - assert!( - find( - &entries, - "gamecult.epiphany.workspace_coverage_receipt", - "current" - ) - .is_none() - ); - assert!( - find( - &entries, - "gamecult.epiphany.workspace_coverage_head", - "current" - ) - .is_none() - ); - Ok(()) - } - - #[test] - fn exact_observation_commits_receipt_and_hostile_point_sets_terminalize() -> Result<()> { - for hostility in [ - Hostility::Honest, - Hostility::IncompatibleCollection, - Hostility::WrongPayload, - Hostility::Extra, - Hostility::Missing, - Hostility::Duplicate, - Hostility::MissingVector, - Hostility::WrongVector, - Hostility::WrongVectorDimension, - Hostility::NonFiniteVector, - ] { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("source.rs"), "fn one() {}\n")?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "projection-execution-runtime".into(), - display_name: "projection execution".into(), - created_at: "2026-07-15T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm( - &runtime, - "projection-execution-swarm", - "2026-07-15T00:00:01Z", - )?; - crate::bind_repository_body( - repo.path(), - &body, - &runtime, - "projection-execution-workspace", - )?; - let coverage = std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"); - crate::bind_runtime_workspace_coverage_store( - &runtime, - &coverage, - "2026-07-15T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let inputs = projection_inputs(&acquisition, repo.path())?; - let body_bytes_before = std::fs::read(&acquisition.body_store)?; - let result = execute_preembedded_workspace_coverage_projection( - &acquisition, - inputs, - &mut FakeProjectionPort::new(hostility), - ); - let entries = acquisition.coverage_store.pull_all()?; - assert_eq!(std::fs::read(&acquisition.body_store)?, body_bytes_before); - assert!(entries.iter().all(|entry| !matches!( - entry.r#type.as_str(), - BODY_BINDING_TYPE | BODY_HEAD_TYPE | BODY_OBSERVATION_TYPE | BODY_MANIFEST_TYPE - ))); - let body_entries = - SingleFileMessagePackBackingStore::new(&acquisition.body_store).pull_all()?; - assert!( - body_entries.iter().all(|entry| !entry - .r#type - .starts_with("gamecult.epiphany.workspace_coverage")), - "workspace coverage authority contaminated the read-only Body store" - ); - match hostility { - Hostility::Honest => { - let receipt = result?; - assert!(find(&entries, RECEIPT_TYPE, &receipt.receipt_id).is_some()); - assert!(find(&entries, HEAD_TYPE, HEAD_KEY).is_some()); - let body = RepositoryBodyReadSession::open(&runtime, &basis)?; - let prepared = - prepare_workspace_coverage_projection(&body, "provider", "model", 3)?; - match acquire_workspace_coverage_projection( - &prepared, - &acquisition.coverage_store, - "replacement-executor", - "replacement-incarnation", - "replacement-startup-receipt", - )? { - WorkspaceCoverageAcquireResult::Current(current) => { - assert_eq!(current, receipt) - } - WorkspaceCoverageAcquireResult::Acquired(_) => { - bail!("exact current projection was claimed again") - } - WorkspaceCoverageAcquireResult::Contended => { - bail!("exact current projection was contended") - } - } - let backing = acquisition.coverage_store.clone(); - let before_corruption = backing.pull_all()?; - let receipt_env = find(&before_corruption, RECEIPT_TYPE, &receipt.receipt_id) - .unwrap() - .clone(); - let mut substituted = receipt.clone(); - substituted.observed_point_count += 1; - assert!(backing.compare_and_swap_batch( - std::slice::from_ref(&receipt_env), - vec![envelope(RECEIPT_TYPE, &receipt.receipt_id, &substituted)?], - )?); - assert!( - acquire_workspace_coverage_projection( - &prepared, - &acquisition.coverage_store, - "replacement-executor", - "replacement-incarnation", - "replacement-startup-receipt", - ) - .is_err() - ); - } - _ => { - assert!(result.is_err()); - assert!(find(&entries, RECEIPT_TYPE, HEAD_KEY).is_none()); - let claim: WorkspaceCoverageProjectionClaim = - decode(find(&entries, CLAIM_TYPE, &acquisition.claim_key).unwrap())?; - assert_eq!(claim.status, "failed"); - } - } - } - Ok(()) - } - - #[test] - fn body_advance_prevents_receipt_and_terminalizes_attempt() -> Result<()> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("source.rs"), "fn one() {}\n")?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "body-advance-runtime".into(), - display_name: "body advance".into(), - created_at: "2026-07-15T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "body-advance-swarm", "2026-07-15T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "body-advance-workspace")?; - crate::bind_runtime_workspace_coverage_store( - &runtime, - std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"), - "2026-07-15T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let inputs = projection_inputs(&acquisition, repo.path())?; - std::fs::write(repo.path().join("source.rs"), "fn two() {}\n")?; - crate::observe_runtime_repository_body_basis(&runtime)?; - assert!( - execute_preembedded_workspace_coverage_projection( - &acquisition, - inputs, - &mut FakeProjectionPort::new(Hostility::Honest) - ) - .is_err() - ); - let entries = acquisition.coverage_store.pull_all()?; - assert!(find(&entries, HEAD_TYPE, HEAD_KEY).is_none()); - let claim: WorkspaceCoverageProjectionClaim = - decode(find(&entries, CLAIM_TYPE, &acquisition.claim_key).unwrap())?; - assert_eq!(claim.status, "failed"); - Ok(()) - } - - #[test] - fn terminal_cas_loser_and_forged_observation_cannot_mint_receipts() -> Result<()> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("source.rs"), "fn one() {}\n")?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "cas-loser-runtime".into(), - display_name: "cas loser".into(), - created_at: "2026-07-15T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "cas-loser-swarm", "2026-07-15T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "cas-loser-workspace")?; - crate::bind_runtime_workspace_coverage_store( - &runtime, - std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"), - "2026-07-15T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let collection_name = workspace_coverage_execution_collection( - &acquisition.plan.plan_id, - &acquisition.claim.claim_id, - acquisition.claim.claim_epoch, - )?; - let forged = WorkspaceCoverageObservedBinding { - collection_name: collection_name.clone(), - point_count: acquisition.plan.expected_point_count, - point_set_sha256: acquisition.plan.expected_point_set_sha256.clone(), - point_binding_set_sha256: "ff".repeat(32), - vector_binding_set_sha256: "ee".repeat(32), - }; - assert!(commit_workspace_coverage_success(&acquisition, forged).is_err()); - fail_workspace_coverage_projection(&acquisition, "another terminal writer won")?; - let exact_but_late = WorkspaceCoverageObservedBinding { - collection_name, - point_count: acquisition.plan.expected_point_count, - point_set_sha256: acquisition.plan.expected_point_set_sha256.clone(), - point_binding_set_sha256: acquisition.plan.point_binding_set_sha256.clone(), - vector_binding_set_sha256: "ee".repeat(32), - }; - assert!(commit_workspace_coverage_success(&acquisition, exact_but_late).is_err()); - let entries = acquisition.coverage_store.pull_all()?; - assert!(find(&entries, HEAD_TYPE, HEAD_KEY).is_none()); - assert!(!entries.iter().any(|entry| entry.r#type == RECEIPT_TYPE)); - Ok(()) - } - - #[test] - fn empty_plan_observes_empty_collection_without_empty_upsert() -> Result<()> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("empty.txt"), "")?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "empty-runtime".into(), - display_name: "empty".into(), - created_at: "2026-07-15T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "empty-swarm", "2026-07-15T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "empty-workspace")?; - crate::bind_runtime_workspace_coverage_store( - &runtime, - std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"), - "2026-07-15T00:00:02Z", - )?; - let basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - assert!(acquisition.plan.planned_points.is_empty()); - let mut port = FakeProjectionPort::new(Hostility::Honest); - let receipt = - execute_preembedded_workspace_coverage_projection(&acquisition, Vec::new(), &mut port)?; - assert_eq!(port.upsert_calls, 0); - assert_eq!(receipt.observed_point_count, 0); - Ok(()) - } - - #[test] - fn successive_generations_replace_only_the_acquired_prior_head() -> Result<()> { - let repo = tempfile::tempdir()?; - let state = tempfile::tempdir()?; - git(repo.path(), &["init"])?; - std::fs::write(repo.path().join("source.rs"), "fn a() {}\n")?; - git(repo.path(), &["add", "."])?; - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "head-cas-runtime".into(), - display_name: "head cas".into(), - created_at: "2026-07-15T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "head-cas-swarm", "2026-07-15T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "head-cas-workspace")?; - crate::bind_runtime_workspace_coverage_store( - &runtime, - std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"), - "2026-07-15T00:00:02Z", - )?; - - let basis_a = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, acquisition_a) = acquire_test(&runtime, &basis_a, "provider", "model", 3)?; - let inputs_a = projection_inputs(&acquisition_a, repo.path())?; - execute_preembedded_workspace_coverage_projection( - &acquisition_a, - inputs_a, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - let backing = acquisition_a.coverage_store.clone(); - let after_a = backing.pull_all()?; - let head_a = find(&after_a, HEAD_TYPE, HEAD_KEY).unwrap().clone(); - - std::fs::write(repo.path().join("source.rs"), "fn b() {}\n")?; - let basis_b = crate::observe_runtime_repository_body_basis(&runtime)?; - let prepared_b = prepare_workspace_coverage_projection( - &RepositoryBodyReadSession::open(&runtime, &basis_b)?, - "provider", - "model", - 3, - )?; - let (_, acquisition_b) = - acquire_test_with_store(prepared_b, &acquisition_a.coverage_store)?; - assert_eq!(acquisition_b.prior_head.as_ref(), Some(&head_a)); - let inputs_b = projection_inputs(&acquisition_b, repo.path())?; - execute_preembedded_workspace_coverage_projection( - &acquisition_b, - inputs_b, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - let after_b = backing.pull_all()?; - let head_b = find(&after_b, HEAD_TYPE, HEAD_KEY).unwrap().clone(); - let decoded_b: WorkspaceCoverageHead = decode(&head_b)?; - assert_eq!(decoded_b.body_generation, basis_b.generation); - - std::fs::write(repo.path().join("source.rs"), "fn c() {}\n")?; - let basis_c = crate::observe_runtime_repository_body_basis(&runtime)?; - let prepared_c = prepare_workspace_coverage_projection( - &RepositoryBodyReadSession::open(&runtime, &basis_c)?, - "provider", - "model", - 3, - )?; - let (_, acquisition_c) = - acquire_test_with_store(prepared_c, &acquisition_a.coverage_store)?; - assert_eq!(acquisition_c.prior_head.as_ref(), Some(&head_b)); - assert!(backing.compare_and_swap_batch(&[head_b], vec![head_a.clone()])?); - let inputs_c = projection_inputs(&acquisition_c, repo.path())?; - assert!( - execute_preembedded_workspace_coverage_projection( - &acquisition_c, - inputs_c, - &mut FakeProjectionPort::new(Hostility::Honest) - ) - .is_err() - ); - let final_entries = backing.pull_all()?; - assert_eq!(find(&final_entries, HEAD_TYPE, HEAD_KEY), Some(&head_a)); - assert!( - !final_entries - .iter() - .filter(|entry| entry.r#type == RECEIPT_TYPE) - .any(|entry| decode::(entry) - .is_ok_and(|receipt| receipt.claim_id == acquisition_c.claim.claim_id)) - ); - Ok(()) - } - - #[test] - fn retention_bounds_retired_generations_to_one_accumulator_without_touching_body() -> Result<()> - { - let (repo, _state, runtime, mut basis) = coverage_fixture()?; - let mut retired_claims = Vec::new(); - let mut retention_sequences = Vec::new(); - for generation in 1..=4 { - if generation > 1 { - std::fs::write( - repo.path().join("source.rs"), - format!("fn generation_{generation}() {{}}\n"), - )?; - basis = crate::observe_runtime_repository_body_basis(&runtime)?; - } - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - let claim_id = acquisition.claim.claim_id.clone(); - execute_preembedded_workspace_coverage_projection( - &acquisition, - projection_inputs(&acquisition, repo.path())?, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - retired_claims.push(claim_id); - drop(acquisition); - let authority = crate::open_workspace_coverage_authority(&runtime)?; - retire_workspace_coverage_collections(&authority, &mut FakeRetirementPort::default())?; - let result = compact_workspace_coverage_history(&runtime, &authority)?; - let opening = authority.store.pull_all()?; - let retention = find(&opening, RETENTION_HEAD_TYPE, RETENTION_HEAD_KEY) - .map(decode::) - .transpose()?; - if let Some(retention) = retention { - retention_sequences.push(retention.sequence); - } - if generation >= 3 { - assert_eq!(result, WorkspaceCoverageRetentionResult::Compacted); - assert!(!opening.iter().any(|entry| { - entry.r#type == CLAIM_TYPE - && decode::(entry) - .is_ok_and(|claim| claim.claim_id == retired_claims[generation - 3]) - })); - assert!(opening.iter().any(|entry| { - entry.r#type == CLAIM_TYPE - && decode::(entry) - .is_ok_and(|claim| claim.claim_id == retired_claims[generation - 2]) - })); - let current_claim: WorkspaceCoverageProjectionClaim = decode( - find( - &opening, - CLAIM_TYPE, - &workspace_coverage_claim_key(&basis.observation_id, basis.generation), - ) - .expect("current terminal claim must remain reachable"), - )?; - assert_eq!(current_claim.status, "succeeded"); - } else { - assert_eq!(result, WorkspaceCoverageRetentionResult::Noop); - } - assert_eq!( - opening - .iter() - .filter(|entry| entry.r#type == RETENTION_HEAD_TYPE) - .count(), - usize::from(generation >= 3) - ); - drop(authority); - } - assert_eq!(retention_sequences, vec![1, 2]); - let route = runtime_repository_body_store_binding(&runtime)?.expect("Body route"); - let body = SingleFileMessagePackBackingStore::new(route.body_store_path).pull_all()?; - assert!(body.iter().all(|entry| entry.r#type != RETENTION_HEAD_TYPE)); - - let authority = crate::open_workspace_coverage_authority(&runtime)?; - let opening = authority.store.pull_all()?; - let prior_env = find(&opening, RETENTION_HEAD_TYPE, RETENTION_HEAD_KEY) - .expect("retention head") - .clone(); - let mut forked: WorkspaceCoverageRetentionHead = decode(&prior_env)?; - let mut duplicate_family = forked.clone(); - duplicate_family - .family_counts - .push(duplicate_family.family_counts[0].clone()); - assert!(validate_retention_head(&duplicate_family, &authority).is_err()); - forked.coverage_binding_id.push_str("-fork"); - assert!(validate_retention_head(&forked, &authority).is_err()); - let mut frontier_fork: WorkspaceCoverageRetentionHead = decode(&prior_env)?; - frontier_fork.compacted_through_body_generation = u64::MAX; - assert!(authority.store.compare_and_swap_entry( - &prior_env, - envelope(RETENTION_HEAD_TYPE, RETENTION_HEAD_KEY, &frontier_fork)?, - )?); - drop(authority); - std::fs::write(repo.path().join("source.rs"), "fn generation_5() {}\n")?; - basis = crate::observe_runtime_repository_body_basis(&runtime)?; - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - execute_preembedded_workspace_coverage_projection( - &acquisition, - projection_inputs(&acquisition, repo.path())?, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - drop(acquisition); - let authority = crate::open_workspace_coverage_authority(&runtime)?; - retire_workspace_coverage_collections(&authority, &mut FakeRetirementPort::default())?; - let before_refusal = authority.store.pull_all()?; - assert!(compact_workspace_coverage_history(&runtime, &authority).is_err()); - assert_eq!(authority.store.pull_all()?, before_refusal); - Ok(()) - } - - #[test] - fn retention_head_alone_grants_no_current_readiness_terminal_or_recovery_authority() - -> Result<()> { - let (_repo, _state, runtime, basis) = coverage_fixture()?; - let authority = crate::open_workspace_coverage_authority(&runtime)?; - let digest = format!("sha256-{}", "00".repeat(32)); - let head = WorkspaceCoverageRetentionHead { - schema_version: RETENTION_HEAD_SCHEMA.into(), - sequence: 1, - prior_head_envelope_sha256: None, - runtime_id: authority.store_binding.runtime_id.clone(), - workspace_id: authority.store_binding.workspace_id.clone(), - coverage_binding_id: authority.store_binding.binding_id.clone(), - coverage_binding_envelope_sha256: authority.store_binding_envelope_sha256.clone(), - coverage_store_file_identity: authority.store.file_identity().into(), - retired_envelope_count: 12, - retired_identity_digest_root: digest.clone(), - family_counts: vec![format!("{CLAIM_TYPE}=12")], - family_digest_roots: vec![format!("{CLAIM_TYPE}={digest}")], - compacted_body_evidence_root: digest.clone(), - compacted_plan_evidence_root: digest.clone(), - compacted_claim_evidence_root: digest.clone(), - compacted_receipt_evidence_root: digest.clone(), - compacted_collection_retirement_evidence_root: digest, - compacted_through_body_generation: basis.generation, - }; - assert!(authority.store.insert_entry_if_absent(envelope( - RETENTION_HEAD_TYPE, - RETENTION_HEAD_KEY, - &head, - )?)?); - assert!(matches!( - classify_current_workspace_coverage( - &runtime, - &authority.store, - &basis, - "provider", - "model", - 3, - )?, - WorkspaceCoverageCurrentState::NeedsPreparation - )); - assert!( - authenticate_current_workspace_coverage_terminal_authority_with_store( - &runtime, - &authority.store, - )? - .is_none() - ); - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0( - WORKSPACE_COVERAGE_MAXIMUM_FILE_BYTES, - )?; - assert!( - observe_current_workspace_coverage_evidence_with_store( - &runtime, - &authority.store, - &basis, - &policy, - "provider", - "model", - 3, - &mut FakeProjectionPort::new(Hostility::Honest), - )? - .is_none() - ); - drop(authority); - Ok(()) - } - - #[test] - fn retention_refuses_unknown_projection_rows_before_any_deletion() -> Result<()> { - let (repo, _state, runtime, mut basis) = coverage_fixture()?; - for generation in 1..=3 { - if generation > 1 { - std::fs::write( - repo.path().join("source.rs"), - format!("fn g{generation}() {{}}"), - )?; - basis = crate::observe_runtime_repository_body_basis(&runtime)?; - } - let (_, acquisition) = acquire_test(&runtime, &basis, "provider", "model", 3)?; - execute_preembedded_workspace_coverage_projection( - &acquisition, - projection_inputs(&acquisition, repo.path())?, - &mut FakeProjectionPort::new(Hostility::Honest), - )?; - drop(acquisition); - let authority = crate::open_workspace_coverage_authority(&runtime)?; - retire_workspace_coverage_collections(&authority, &mut FakeRetirementPort::default())?; - if generation == 3 { - let opening = authority.store.pull_all()?; - let evidence_env = opening - .iter() - .find(|entry| entry.r#type == COLLECTION_RETIREMENT_EVIDENCE_TYPE) - .expect("retirement evidence") - .clone(); - let mut substituted: WorkspaceCoverageCollectionRetirementEvidence = - decode(&evidence_env)?; - substituted.observed_result = "assumed-absent".into(); - let substituted_env = envelope( - COLLECTION_RETIREMENT_EVIDENCE_TYPE, - &evidence_env.key, - &substituted, - )?; - assert!( - authority - .store - .compare_and_swap_entry(&evidence_env, substituted_env.clone())? - ); - let before = authority.store.pull_all()?; - assert!(compact_workspace_coverage_history(&runtime, &authority).is_err()); - assert_eq!(authority.store.pull_all()?, before); - assert!( - authority - .store - .compare_and_swap_entry(&substituted_env, evidence_env)? - ); - - let malformed = CultCacheEnvelope { - r#type: CLAIM_TYPE.into(), - key: "malformed-known-row".into(), - schema_id: Some(CLAIM_SCHEMA.into()), - payload: vec![1, 2, 3], - stored_at: chrono::Utc::now().to_rfc3339(), - }; - assert!(authority.store.insert_entry_if_absent(malformed.clone())?); - let before = authority.store.pull_all()?; - assert!(compact_workspace_coverage_history(&runtime, &authority).is_err()); - assert_eq!(authority.store.pull_all()?, before); - assert!( - authority - .store - .delete_batch_if_unchanged(std::slice::from_ref(&malformed))? - ); - - let unknown = CultCacheEnvelope { - r#type: "gamecult.epiphany.workspace_coverage_alien".into(), - key: "current".into(), - schema_id: Some("alien.v0".into()), - payload: vec![1, 2, 3], - stored_at: chrono::Utc::now().to_rfc3339(), - }; - assert!(authority.store.insert_entry_if_absent(unknown)?); - let before = authority.store.pull_all()?; - assert!(compact_workspace_coverage_history(&runtime, &authority).is_err()); - assert_eq!(authority.store.pull_all()?, before); - } - drop(authority); - } - Ok(()) - } -} diff --git a/epiphany-core/src/workspace_coverage_projector_service.rs b/epiphany-core/src/workspace_coverage_projector_service.rs deleted file mode 100644 index 280cadd6..00000000 --- a/epiphany-core/src/workspace_coverage_projector_service.rs +++ /dev/null @@ -1,495 +0,0 @@ -use crate::repository_body_observer::RepositoryBodyReadSession; -use crate::semantic_backend::{OllamaConfig, OllamaEmbedder, QdrantBackend, QdrantConfig}; -use crate::workspace_coverage_process_documents::{ - authenticate_workspace_coverage_recovery_directive, publish_workspace_coverage_claim_sight, - publish_workspace_coverage_terminal_sight, -}; -use crate::workspace_coverage_projector::{ - WorkspaceCoverageAcquireResult, WorkspaceCoverageCurrentState, - WorkspaceCoverageProjectionExecutionAuthority, acquire_workspace_coverage_projection, - classify_current_workspace_coverage, compact_workspace_coverage_history, - execute_workspace_coverage_projection, prepare_workspace_coverage_projection, - retire_workspace_coverage_collections, -}; -use crate::{ - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, HostIncarnationIdentityEntry, - WorkspaceCoverageAuthority, load_current_runtime_repository_body_basis, - open_workspace_coverage_authority, runtime_repository_body_store_binding, -}; -use anyhow::{Context, Result, anyhow, bail}; -use ed25519_dalek::SigningKey; -use std::path::{Path, PathBuf}; -use uuid::Uuid; - -const EMBEDDING_PROVIDER_ID: &str = "gamecult-ollama-embedding"; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageProjectorConfig { - pub qdrant_url: String, - pub qdrant_api_key: Option, - pub qdrant_timeout_ms: u64, - pub ollama_base_url: String, - pub ollama_model: String, - pub ollama_timeout_ms: u64, -} - -impl WorkspaceCoverageProjectorConfig { - pub fn from_env() -> Self { - let semantic = crate::MemorySemanticIndexConfig::from_env(); - Self { - qdrant_url: semantic.qdrant_url, - qdrant_api_key: semantic.qdrant_api_key, - qdrant_timeout_ms: semantic.qdrant_timeout_ms, - ollama_base_url: semantic.ollama_base_url, - ollama_model: semantic.ollama_model, - ollama_timeout_ms: semantic.ollama_timeout_ms, - } - } - - fn validate(&self) -> Result<()> { - for (label, value) in [ - ("Qdrant URL", self.qdrant_url.as_str()), - ("Ollama base URL", self.ollama_base_url.as_str()), - ("Ollama model", self.ollama_model.as_str()), - ] { - if value.trim().is_empty() { - bail!("workspace coverage projector requires a non-empty {label}"); - } - } - if self.qdrant_timeout_ms == 0 || self.ollama_timeout_ms == 0 { - bail!("workspace coverage projector timeouts must be positive"); - } - Ok(()) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum WorkspaceCoverageProjectorPulseStatus { - Idle, - Executed, - Contended, - Refused, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct WorkspaceCoverageProjectorServicePulse { - pub status: WorkspaceCoverageProjectorPulseStatus, - pub body_observation_id: Option, - pub body_generation: Option, - pub plan_id: Option, - pub receipt_id: Option, - pub fault: Option, -} - -pub struct WorkspaceCoverageProjectorServiceBody { - coverage_authority: WorkspaceCoverageAuthority, - runtime_store: PathBuf, - executor_incarnation: String, - managed_process_launch_id: String, - embedder: OllamaEmbedder, - qdrant: QdrantBackend, - execution_authority: Option, - operation_timeout_ms: u64, -} - -#[derive(Clone)] -struct WorkspaceCoverageProjectorExecutionAuthority { - local_verse_store: PathBuf, - runtime_id: String, - trusted_host: HostIncarnationIdentityEntry, - provider_signing_key: SigningKey, -} - -impl WorkspaceCoverageProjectorServiceBody { - pub fn new( - runtime_store: impl AsRef, - runtime_id: impl Into, - config: WorkspaceCoverageProjectorConfig, - executor_incarnation: impl Into, - managed_process_launch_id: impl Into, - ) -> Result { - config.validate()?; - let executor_incarnation = executor_incarnation.into(); - if executor_incarnation.trim().is_empty() { - bail!("workspace coverage projector requires its executor incarnation"); - } - let managed_process_launch_id = managed_process_launch_id.into(); - Uuid::parse_str(&managed_process_launch_id).context( - "workspace coverage projector requires its authenticated managed process launch id", - )?; - let runtime_id = runtime_id.into(); - if runtime_id.trim().is_empty() { - bail!("workspace coverage projector requires its CultMesh runtime id"); - } - let runtime_store = runtime_store - .as_ref() - .canonicalize() - .context("workspace coverage projector runtime store is missing")?; - if !runtime_store.is_file() { - bail!("workspace coverage projector runtime store is not a file"); - } - let route = runtime_repository_body_store_binding(&runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - if route.runtime_id != runtime_id { - bail!( - "workspace coverage projector runtime Body route disagrees with authenticated runtime id" - ); - } - let coverage_authority = open_workspace_coverage_authority(&runtime_store)?; - let operation_timeout_ms = config.qdrant_timeout_ms; - let qdrant = QdrantBackend::new(QdrantConfig { - url: config.qdrant_url, - api_key: config.qdrant_api_key, - timeout_ms: config.qdrant_timeout_ms, - })?; - let embedder = OllamaEmbedder::new(OllamaConfig { - base_url: config.ollama_base_url, - model: config.ollama_model, - timeout_ms: config.ollama_timeout_ms, - query_instruction: String::new(), - })?; - Ok(Self { - coverage_authority, - runtime_store, - executor_incarnation, - managed_process_launch_id, - embedder, - qdrant, - execution_authority: None, - operation_timeout_ms, - }) - } - - pub fn install_execution_authority( - &mut self, - local_verse_store: impl AsRef, - runtime_id: impl Into, - trusted_host: HostIncarnationIdentityEntry, - provider_signing_key: SigningKey, - ) -> Result<()> { - let runtime_id = runtime_id.into(); - if runtime_id.trim().is_empty() { - bail!("workspace coverage execution authority requires its runtime id"); - } - let bound = runtime_repository_body_store_binding(&self.runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - if bound.runtime_id != runtime_id { - bail!("workspace coverage execution authority runtime disagrees with Body route"); - } - self.execution_authority = Some(WorkspaceCoverageProjectorExecutionAuthority { - local_verse_store: local_verse_store.as_ref().to_path_buf(), - runtime_id, - trusted_host, - provider_signing_key, - }); - Ok(()) - } - - pub fn provider_incarnation(&self) -> &str { - &self.executor_incarnation - } - - pub fn managed_process_launch_id(&self) -> &str { - &self.managed_process_launch_id - } - - pub fn pulse(&mut self) -> WorkspaceCoverageProjectorServicePulse { - match self.pulse_inner() { - Ok(pulse) => pulse, - Err(_error) => { - eprintln!("workspace coverage pulse failed: {_error:#}"); - WorkspaceCoverageProjectorServicePulse { - status: WorkspaceCoverageProjectorPulseStatus::Refused, - body_observation_id: None, - body_generation: None, - plan_id: None, - receipt_id: None, - // Managed stdout is an operator-safe projection. Raw backend - // bodies and filesystem paths remain private to the process. - fault: Some("workspace_coverage_pulse_refused".into()), - } - } - } - } - - fn pulse_inner(&mut self) -> Result { - let authority = self.execution_authority.as_ref().ok_or_else(|| { - anyhow!("workspace coverage projector has no installed execution authority") - })?; - // Retirement is derived from typed Body history and is deliberately - // performed before the idle fast path. Qdrant never nominates its own - // garbage and incompatible same-name collections stop the pulse. - retire_workspace_coverage_collections(&self.coverage_authority, &mut self.qdrant)?; - let _ = compact_workspace_coverage_history(&self.runtime_store, &self.coverage_authority)?; - let basis = load_current_runtime_repository_body_basis(&self.runtime_store)?; - // Tags are mutable. Re-resolve the installed artifact every pulse so a - // same-dimensional model replacement cannot reuse an older index. - let embedding_model_identity = self.embedder.model_artifact()?.canonical_identity(); - let dimensions = self.embedder.embedding_dimensions()?; - if let WorkspaceCoverageCurrentState::Current(receipt) = - classify_current_workspace_coverage( - &self.runtime_store, - &self.coverage_authority.store, - &basis, - EMBEDDING_PROVIDER_ID, - &embedding_model_identity, - dimensions, - )? - { - let authority = self.execution_authority.as_ref().ok_or_else(|| { - anyhow!("workspace coverage projector has no installed execution authority") - })?; - publish_workspace_coverage_terminal_sight( - &authority.local_verse_store, - &self.runtime_store, - &self.coverage_authority, - &authority.runtime_id, - &self.managed_process_launch_id, - &authority.trusted_host, - &authority.provider_signing_key, - chrono::Utc::now(), - )?; - return Ok(WorkspaceCoverageProjectorServicePulse { - status: WorkspaceCoverageProjectorPulseStatus::Idle, - body_observation_id: Some(basis.observation_id), - body_generation: Some(basis.generation), - plan_id: Some(receipt.plan_id.clone()), - receipt_id: Some(receipt.receipt_id), - fault: None, - }); - } - // A durable terminal projection outranks process recovery. Its signed - // historical sight remains valid across managed-policy rotation; a new - // daemon observes that fact but does not take ownership of the old - // succeeded claim. Recovery still precedes all nonterminal claim work. - if let Some(directive) = authenticate_workspace_coverage_recovery_directive( - &authority.local_verse_store, - &self.runtime_store, - &authority.runtime_id, - &self.managed_process_launch_id, - &authority.trusted_host, - )? { - if directive.workspace_id != basis.workspace_id - || directive.body_binding_sha256 != basis.body_binding_sha256 - || directive.body_observation_id != basis.observation_id - || directive.body_generation != basis.generation - || directive.manifest_root_sha256 != basis.manifest_root_sha256 - || directive.coverage_store_binding_id - != self.coverage_authority.store_binding.binding_id - || directive.coverage_store_binding_envelope_digest - != self.coverage_authority.store_binding_envelope_sha256 - || directive.coverage_store_file_identity - != self.coverage_authority.store_binding.store_file_identity - || directive.runtime_coverage_route_envelope_digest - != self - .coverage_authority - .runtime_coverage_route_envelope_sha256 - { - bail!("workspace coverage recovery directive disagrees with held authority"); - } - crate::workspace_coverage_projector::recover_workspace_coverage_projection_with_authority( - &self.coverage_authority, &self.runtime_store, &authority.local_verse_store, - &authority.runtime_id, &authority.trusted_host, &directive.old_launch_id, - &directive.replacement_launch_id, &directive.replacement_ready_heartbeat_id, - &directive.old_claim_id, - )?; - } - let body = RepositoryBodyReadSession::open(&self.runtime_store, &basis)?; - let prepared = prepare_workspace_coverage_projection( - &body, - EMBEDDING_PROVIDER_ID, - &embedding_model_identity, - dimensions, - )?; - let plan_id = prepared.plan.plan_id.clone(); - match acquire_workspace_coverage_projection( - &prepared, - &self.coverage_authority.store, - EPIPHANY_WORKSPACE_COVERAGE_PROJECTOR_DAEMON_ID, - &self.executor_incarnation, - &self.managed_process_launch_id, - )? { - WorkspaceCoverageAcquireResult::Contended => { - Ok(WorkspaceCoverageProjectorServicePulse { - status: WorkspaceCoverageProjectorPulseStatus::Contended, - body_observation_id: Some(basis.observation_id), - body_generation: Some(basis.generation), - plan_id: Some(plan_id), - receipt_id: None, - fault: None, - }) - } - WorkspaceCoverageAcquireResult::Current(receipt) => { - let authority = self.execution_authority.as_ref().ok_or_else(|| { - anyhow!("workspace coverage projector has no installed execution authority") - })?; - publish_workspace_coverage_terminal_sight( - &authority.local_verse_store, - &self.runtime_store, - &self.coverage_authority, - &authority.runtime_id, - &self.managed_process_launch_id, - &authority.trusted_host, - &authority.provider_signing_key, - chrono::Utc::now(), - )?; - Ok(WorkspaceCoverageProjectorServicePulse { - status: WorkspaceCoverageProjectorPulseStatus::Idle, - body_observation_id: Some(basis.observation_id), - body_generation: Some(basis.generation), - plan_id: Some(plan_id), - receipt_id: Some(receipt.receipt_id), - fault: None, - }) - } - WorkspaceCoverageAcquireResult::Acquired(acquisition) => { - let authority = self.execution_authority.as_ref().ok_or_else(|| { - anyhow!("workspace coverage projector has no installed execution authority") - })?; - // Publish the exact provider-signed lease before the first backend - // operation. Recovery sight must exist even when the projector dies - // before it can mint a progress checkpoint. - publish_workspace_coverage_claim_sight( - &authority.local_verse_store, - &self.runtime_store, - &self.coverage_authority, - &acquisition, - &authority.runtime_id, - &self.managed_process_launch_id, - &authority.trusted_host, - &authority.provider_signing_key, - chrono::Utc::now(), - )?; - let receipt = execute_workspace_coverage_projection( - &acquisition, - &prepared, - &self.embedder, - &mut self.qdrant, - &WorkspaceCoverageProjectionExecutionAuthority { - coverage_authority: &self.coverage_authority, - runtime_store: &self.runtime_store, - local_verse_store: &authority.local_verse_store, - runtime_id: &authority.runtime_id, - trusted_host: &authority.trusted_host, - provider_signing_key: &authority.provider_signing_key, - operation_timeout_ms: self.operation_timeout_ms, - }, - )?; - Ok(WorkspaceCoverageProjectorServicePulse { - status: WorkspaceCoverageProjectorPulseStatus::Executed, - body_observation_id: Some(basis.observation_id), - body_generation: Some(basis.generation), - plan_id: Some(plan_id), - receipt_id: Some(receipt.receipt_id), - fault: None, - }) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn config() -> WorkspaceCoverageProjectorConfig { - WorkspaceCoverageProjectorConfig { - qdrant_url: "http://127.0.0.1:6333".into(), - qdrant_api_key: None, - qdrant_timeout_ms: 1, - ollama_base_url: "http://127.0.0.1:11434".into(), - ollama_model: "test-model".into(), - ollama_timeout_ms: 1, - } - } - - #[test] - fn config_refuses_empty_endpoints_and_zero_timeouts() { - let mut value = config(); - value.ollama_model.clear(); - assert!(value.validate().is_err()); - let mut value = config(); - value.qdrant_timeout_ms = 0; - assert!(value.validate().is_err()); - } - - #[test] - fn constructor_requires_lifecycle_identity_before_touching_runtime() { - assert!( - WorkspaceCoverageProjectorServiceBody::new( - "missing", - "runtime", - config(), - "", - "not-a-uuid" - ) - .is_err() - ); - assert!( - WorkspaceCoverageProjectorServiceBody::new( - "missing", - "runtime", - config(), - "incarnation", - "not-a-uuid", - ) - .is_err() - ); - } - - #[test] - fn live_service_exclusively_owns_the_bound_coverage_store() -> Result<()> { - let state = tempfile::tempdir()?; - let repo = tempfile::tempdir()?; - let initialized = std::process::Command::new("git") - .arg("init") - .current_dir(repo.path()) - .output()?; - if !initialized.status.success() { - bail!("singleton fixture failed to initialize repository"); - } - let runtime = state.path().join("runtime.cc"); - let body = state.path().join("body.cc"); - let coverage = std::fs::canonicalize(state.path())?.join("workspace-coverage.cc"); - crate::initialize_runtime_spine( - &runtime, - crate::RuntimeSpineInitOptions { - runtime_id: "singleton-runtime".into(), - display_name: "singleton test".into(), - created_at: "2026-07-17T00:00:00Z".into(), - }, - )?; - crate::bind_runtime_to_swarm(&runtime, "singleton-swarm", "2026-07-17T00:00:01Z")?; - crate::bind_repository_body(repo.path(), &body, &runtime, "singleton-workspace")?; - crate::bind_runtime_workspace_coverage_store(&runtime, &coverage, "2026-07-17T00:00:02Z")?; - let launch_id = "019bff10-7426-7a1c-9ce4-33f91660a3a7"; - let first = WorkspaceCoverageProjectorServiceBody::new( - &runtime, - "singleton-runtime", - config(), - "first-incarnation", - launch_id, - )?; - assert!( - WorkspaceCoverageProjectorServiceBody::new( - &runtime, - "singleton-runtime", - config(), - "second-incarnation", - launch_id, - ) - .is_err(), - "a second live projector must not acquire the same owned store" - ); - drop(first); - WorkspaceCoverageProjectorServiceBody::new( - &runtime, - "singleton-runtime", - config(), - "replacement-incarnation", - launch_id, - )?; - Ok(()) - } - -} diff --git a/epiphany-core/src/workspace_coverage_store_binding.rs b/epiphany-core/src/workspace_coverage_store_binding.rs deleted file mode 100644 index 61a46fc3..00000000 --- a/epiphany-core/src/workspace_coverage_store_binding.rs +++ /dev/null @@ -1,829 +0,0 @@ -use crate::{ - BODY_BINDING_KEY, BODY_BINDING_TYPE, RUNTIME_BODY_STORE_BINDING_KEY, - RUNTIME_BODY_STORE_BINDING_TYPE, RepositoryBodyBinding, RuntimeRepositoryBodyStoreBinding, - runtime_repository_body_store_binding, -}; -use anyhow::{Context, Result, anyhow, bail}; -use cultcache_rs::{ - CacheBackingStore, CultCacheEnvelope, DatabaseEntry, OwnedRedbMessagePackBackingStore, - SingleFileMessagePackBackingStore, -}; -use serde::{Serialize, de::DeserializeOwned}; -use sha2::{Digest, Sha256}; -use std::path::{Path, PathBuf}; - -pub const RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE: &str = - "epiphany.runtime.workspace_coverage_store_binding"; -pub const RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY: &str = "workspace-coverage-store"; -pub const RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION: &str = - "epiphany.runtime.workspace_coverage_store_binding.v0"; -pub const WORKSPACE_COVERAGE_STORE_BINDING_TYPE: &str = - "gamecult.epiphany.workspace_coverage_store_binding"; -pub const WORKSPACE_COVERAGE_STORE_BINDING_KEY: &str = "binding"; -pub const WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_store_binding.v0"; - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "epiphany.runtime.workspace_coverage_store_binding", - schema = "RuntimeWorkspaceCoverageStoreBinding" -)] -pub struct RuntimeWorkspaceCoverageStoreBinding { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub binding_id: String, - #[cultcache(key = 2)] - pub runtime_id: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub workspace_id: String, - #[cultcache(key = 5)] - pub projection_store_path: String, - #[cultcache(key = 6)] - pub store_file_identity: String, - #[cultcache(key = 7)] - pub repository_body_store_binding_id: String, - #[cultcache(key = 8)] - pub repository_body_store_binding_envelope_sha256: String, - #[cultcache(key = 9)] - pub body_binding_sha256: String, - #[cultcache(key = 10)] - pub created_at_utc: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_store_binding", - schema = "WorkspaceCoverageStoreBinding" -)] -pub struct WorkspaceCoverageStoreBinding { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub binding_id: String, - #[cultcache(key = 2)] - pub runtime_id: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub workspace_id: String, - #[cultcache(key = 5)] - pub store_file_identity: String, - #[cultcache(key = 6)] - pub body_binding_sha256: String, - #[cultcache(key = 7)] - pub repository_source_identity_sha256: String, - #[cultcache(key = 8)] - pub projection_scope: String, - #[cultcache(key = 9)] - pub storage_backend: String, - #[cultcache(key = 10)] - pub created_at_utc: String, -} - -#[derive(Debug)] -pub struct WorkspaceCoverageAuthority { - pub store: OwnedRedbMessagePackBackingStore, - pub runtime_body_route: RuntimeRepositoryBodyStoreBinding, - pub runtime_body_route_envelope: CultCacheEnvelope, - pub runtime_body_route_envelope_sha256: String, - pub body_binding: RepositoryBodyBinding, - pub body_binding_envelope: CultCacheEnvelope, - pub body_binding_envelope_sha256: String, - pub runtime_coverage_route: RuntimeWorkspaceCoverageStoreBinding, - pub runtime_coverage_route_envelope: CultCacheEnvelope, - pub runtime_coverage_route_envelope_sha256: String, - pub store_binding: WorkspaceCoverageStoreBinding, - pub store_binding_envelope: CultCacheEnvelope, - pub store_binding_envelope_sha256: String, -} - -pub fn bind_runtime_workspace_coverage_store( - runtime_store: impl AsRef, - projection_store: impl AsRef, - created_at_utc: &str, -) -> Result { - let runtime_store = runtime_store.as_ref(); - let projection_store = projection_store.as_ref(); - require_timestamp(created_at_utc)?; - - if let Some(existing) = raw_runtime_route(runtime_store)? { - require_same_path(projection_store, Path::new(&existing.projection_store_path))?; - return runtime_workspace_coverage_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime workspace coverage route disappeared during reload")); - } - - let (body_route, body_route_envelope, body, _) = load_body_authority(runtime_store)?; - let canonical_projection_store = canonical_new_store_path(projection_store, &body)?; - let store = OwnedRedbMessagePackBackingStore::new(&canonical_projection_store)?; - require_canonical_existing_outside(store.path(), &body)?; - store.validate_path_identity()?; - let store_file_identity = store.file_identity().to_string(); - let body_route_digest = envelope_sha256(&body_route_envelope)?; - let binding_id = workspace_coverage_binding_id( - &body_route.runtime_id, - &body_route.swarm_id, - &body_route.workspace_id, - &canonical_projection_store, - &store_file_identity, - &body_route_digest, - &body_route.body_binding_sha256, - )?; - let mut local_binding = WorkspaceCoverageStoreBinding { - schema_version: WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION.into(), - binding_id: binding_id.clone(), - runtime_id: body_route.runtime_id.clone(), - swarm_id: body_route.swarm_id.clone(), - workspace_id: body_route.workspace_id.clone(), - store_file_identity: store_file_identity.clone(), - body_binding_sha256: body_route.body_binding_sha256.clone(), - repository_source_identity_sha256: body.source_identity_sha256.clone(), - projection_scope: "workspace_coverage".into(), - storage_backend: "cultcache_redb_v0".into(), - created_at_utc: created_at_utc.to_string(), - }; - let local_envelope = envelope( - WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - WORKSPACE_COVERAGE_STORE_BINDING_KEY, - &local_binding, - created_at_utc, - )?; - if !store.insert_entry_if_absent(local_envelope.clone())? { - let entries = store.pull_all()?; - let existing = find( - &entries, - WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - WORKSPACE_COVERAGE_STORE_BINDING_KEY, - ) - .ok_or_else(|| anyhow!("workspace coverage store binding lost insert race"))?; - let existing: WorkspaceCoverageStoreBinding = decode(existing)?; - require_timestamp(&existing.created_at_utc)?; - local_binding.created_at_utc = existing.created_at_utc.clone(); - if existing != local_binding { - bail!("workspace coverage store immutable binding collision"); - } - local_binding = existing; - } - let timestamp = local_binding.created_at_utc.clone(); - - let runtime_binding = RuntimeWorkspaceCoverageStoreBinding { - schema_version: RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION.into(), - binding_id, - runtime_id: body_route.runtime_id, - swarm_id: body_route.swarm_id, - workspace_id: body_route.workspace_id, - projection_store_path: canonical_projection_store.to_string_lossy().into_owned(), - store_file_identity, - repository_body_store_binding_id: body_route.binding_id, - repository_body_store_binding_envelope_sha256: body_route_digest, - body_binding_sha256: body_route.body_binding_sha256, - created_at_utc: timestamp.clone(), - }; - let runtime_envelope = envelope( - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY, - &runtime_binding, - ×tamp, - )?; - let runtime_backing = SingleFileMessagePackBackingStore::new(runtime_store); - if !runtime_backing.insert_entry_if_absent(runtime_envelope)? { - let existing = raw_runtime_route(runtime_store)? - .ok_or_else(|| anyhow!("runtime workspace coverage binding lost insert race"))?; - if existing != runtime_binding { - bail!("runtime workspace coverage-store immutable binding collision"); - } - } - store.validate_path_identity()?; - let authority = assemble_workspace_coverage_authority(runtime_store, store)?; - let route = authority.runtime_coverage_route.clone(); - drop(authority); - Ok(route) -} - -pub fn runtime_workspace_coverage_store_binding( - runtime_store: impl AsRef, -) -> Result> { - let runtime_store = runtime_store.as_ref(); - let Some(route) = raw_runtime_route(runtime_store)? else { - return Ok(None); - }; - let (body_route, body_route_envelope, _, _) = load_body_authority(runtime_store)?; - validate_runtime_route( - &route, - &body_route, - &body_route_envelope, - &route.store_file_identity, - )?; - Ok(Some(route)) -} - -pub fn open_workspace_coverage_authority( - runtime_store: impl AsRef, -) -> Result { - let runtime_store = runtime_store.as_ref(); - let runtime_route = raw_runtime_route(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no workspace coverage-store binding"))?; - let path = PathBuf::from(&runtime_route.projection_store_path); - let store = OwnedRedbMessagePackBackingStore::new(&path)?; - assemble_workspace_coverage_authority(runtime_store, store) -} - -fn assemble_workspace_coverage_authority( - runtime_store: &Path, - store: OwnedRedbMessagePackBackingStore, -) -> Result { - let (body_route, body_route_envelope, body, body_envelope) = - load_body_authority(runtime_store)?; - let runtime_entries = SingleFileMessagePackBackingStore::new(runtime_store).pull_all()?; - let runtime_envelope = find( - &runtime_entries, - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY, - ) - .cloned() - .ok_or_else(|| anyhow!("runtime has no workspace coverage-store binding"))?; - let runtime_route: RuntimeWorkspaceCoverageStoreBinding = decode(&runtime_envelope)?; - require_same_path( - store.path(), - Path::new(&runtime_route.projection_store_path), - )?; - require_canonical_existing_outside(store.path(), &body)?; - store.validate_path_identity()?; - validate_runtime_route( - &runtime_route, - &body_route, - &body_route_envelope, - store.file_identity(), - )?; - let local_entries = store.pull_all()?; - let local_envelope = find( - &local_entries, - WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - WORKSPACE_COVERAGE_STORE_BINDING_KEY, - ) - .cloned() - .ok_or_else(|| anyhow!("workspace coverage store has no immutable binding"))?; - let local_binding: WorkspaceCoverageStoreBinding = decode(&local_envelope)?; - validate_local_binding(&local_binding, &runtime_route, &body)?; - Ok(WorkspaceCoverageAuthority { - store, - runtime_body_route: body_route, - runtime_body_route_envelope_sha256: envelope_sha256(&body_route_envelope)?, - runtime_body_route_envelope: body_route_envelope, - body_binding: body, - body_binding_envelope_sha256: envelope_sha256(&body_envelope)?, - body_binding_envelope: body_envelope, - runtime_coverage_route: runtime_route, - runtime_coverage_route_envelope_sha256: envelope_sha256(&runtime_envelope)?, - runtime_coverage_route_envelope: runtime_envelope, - store_binding: local_binding, - store_binding_envelope_sha256: envelope_sha256(&local_envelope)?, - store_binding_envelope: local_envelope, - }) -} - -fn load_body_authority( - runtime_store: &Path, -) -> Result<( - RuntimeRepositoryBodyStoreBinding, - CultCacheEnvelope, - RepositoryBodyBinding, - CultCacheEnvelope, -)> { - let body_route = runtime_repository_body_store_binding(runtime_store)? - .ok_or_else(|| anyhow!("runtime has no repository Body-store binding"))?; - let runtime_entries = SingleFileMessagePackBackingStore::new(runtime_store).pull_all()?; - let route_envelope = find( - &runtime_entries, - RUNTIME_BODY_STORE_BINDING_TYPE, - RUNTIME_BODY_STORE_BINDING_KEY, - ) - .cloned() - .ok_or_else(|| anyhow!("runtime repository Body route envelope is missing"))?; - let body_entries = - SingleFileMessagePackBackingStore::new(&body_route.body_store_path).pull_all()?; - let body_envelope = find(&body_entries, BODY_BINDING_TYPE, BODY_BINDING_KEY) - .cloned() - .ok_or_else(|| anyhow!("repository Body binding envelope is missing"))?; - let body: RepositoryBodyBinding = decode(&body_envelope)?; - Ok((body_route, route_envelope, body, body_envelope)) -} - -fn validate_runtime_route( - route: &RuntimeWorkspaceCoverageStoreBinding, - body_route: &RuntimeRepositoryBodyStoreBinding, - body_route_envelope: &CultCacheEnvelope, - owned_store_file_identity: &str, -) -> Result<()> { - require_timestamp(&route.created_at_utc)?; - let path = PathBuf::from(&route.projection_store_path); - let expected_binding_id = workspace_coverage_binding_id( - &body_route.runtime_id, - &body_route.swarm_id, - &body_route.workspace_id, - &path, - owned_store_file_identity, - &envelope_sha256(body_route_envelope)?, - &body_route.body_binding_sha256, - )?; - if route.schema_version != RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION - || route.binding_id != expected_binding_id - || !path.is_absolute() - || route.store_file_identity.trim().is_empty() - || route.runtime_id != body_route.runtime_id - || route.swarm_id != body_route.swarm_id - || route.workspace_id != body_route.workspace_id - || route.store_file_identity != owned_store_file_identity - || route.repository_body_store_binding_id != body_route.binding_id - || route.repository_body_store_binding_envelope_sha256 - != envelope_sha256(body_route_envelope)? - || route.body_binding_sha256 != body_route.body_binding_sha256 - { - bail!("runtime workspace coverage-store binding disagrees with repository Body authority"); - } - Ok(()) -} - -fn validate_local_binding( - local: &WorkspaceCoverageStoreBinding, - route: &RuntimeWorkspaceCoverageStoreBinding, - body: &RepositoryBodyBinding, -) -> Result<()> { - require_timestamp(&local.created_at_utc)?; - if local.schema_version != WORKSPACE_COVERAGE_STORE_BINDING_SCHEMA_VERSION - || local.binding_id != route.binding_id - || local.runtime_id != route.runtime_id - || local.swarm_id != route.swarm_id - || local.workspace_id != route.workspace_id - || local.store_file_identity != route.store_file_identity - || local.body_binding_sha256 != route.body_binding_sha256 - || local.repository_source_identity_sha256 != body.source_identity_sha256 - || local.projection_scope != "workspace_coverage" - || local.storage_backend != "cultcache_redb_v0" - || local.created_at_utc != route.created_at_utc - { - bail!("workspace coverage store binding disagrees with runtime route"); - } - Ok(()) -} - -fn raw_runtime_route(runtime_store: &Path) -> Result> { - if !runtime_store.exists() { - return Ok(None); - } - let entries = SingleFileMessagePackBackingStore::new(runtime_store).pull_all()?; - find( - &entries, - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY, - ) - .map(decode) - .transpose() -} - -fn canonical_new_store_path(path: &Path, body: &RepositoryBodyBinding) -> Result { - if !path.is_absolute() { - bail!("workspace coverage store path must be absolute"); - } - if path.exists() { - return canonical_existing_outside(path, body); - } - let parent = path - .parent() - .ok_or_else(|| anyhow!("workspace coverage store path has no parent"))?; - let canonical_parent = - std::fs::canonicalize(parent).context("workspace coverage store parent is missing")?; - let file_name = path - .file_name() - .ok_or_else(|| anyhow!("workspace coverage store path has no filename"))?; - let canonical = canonical_parent.join(file_name); - require_outside_worktree(&canonical, body)?; - Ok(canonical) -} - -fn require_canonical_existing_outside(path: &Path, body: &RepositoryBodyBinding) -> Result<()> { - canonical_existing_outside(path, body).map(|_| ()) -} - -fn canonical_existing_outside(path: &Path, body: &RepositoryBodyBinding) -> Result { - let canonical = - std::fs::canonicalize(path).context("bound workspace coverage store is missing")?; - require_outside_worktree(&canonical, body)?; - Ok(canonical) -} - -fn require_outside_worktree(path: &Path, body: &RepositoryBodyBinding) -> Result<()> { - let worktree = std::fs::canonicalize(&body.git_top_level) - .context("repository Body worktree is missing")?; - if path.starts_with(&worktree) { - bail!("workspace coverage store must be outside the repository worktree"); - } - Ok(()) -} - -fn require_same_path(requested: &Path, bound: &Path) -> Result<()> { - let requested = std::fs::canonicalize(requested) - .context("requested workspace coverage store is missing")?; - let bound = - std::fs::canonicalize(bound).context("bound workspace coverage store is missing")?; - if requested != bound { - bail!("runtime workspace coverage-store immutable path collision"); - } - Ok(()) -} - -fn require_timestamp(timestamp: &str) -> Result<()> { - chrono::DateTime::parse_from_rfc3339(timestamp) - .map_err(|_| anyhow!("workspace coverage store binding timestamp must be RFC3339"))?; - Ok(()) -} - -fn find<'a>( - entries: &'a [CultCacheEnvelope], - ty: &str, - key: &str, -) -> Option<&'a CultCacheEnvelope> { - entries - .iter() - .find(|entry| entry.r#type == ty && entry.key == key) -} - -fn decode(envelope: &CultCacheEnvelope) -> Result { - rmp_serde::from_slice(&envelope.payload).map_err(Into::into) -} - -fn envelope( - ty: &str, - key: &str, - value: &T, - stored_at: &str, -) -> Result { - Ok(CultCacheEnvelope { - key: key.into(), - r#type: ty.into(), - payload: rmp_serde::to_vec(value)?, - stored_at: stored_at.into(), - schema_id: Some(ty.into()), - }) -} - -fn envelope_sha256(envelope: &CultCacheEnvelope) -> Result { - Ok(format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(envelope)?) - )) -} - -fn workspace_coverage_binding_id( - runtime_id: &str, - swarm_id: &str, - workspace_id: &str, - canonical_projection_store: &Path, - store_file_identity: &str, - body_route_envelope_sha256: &str, - body_binding_sha256: &str, -) -> Result { - let digest = Sha256::digest(rmp_serde::to_vec_named(&( - "gamecult.epiphany.workspace_coverage_store_binding_id.v0", - runtime_id, - swarm_id, - workspace_id, - canonical_projection_store.to_string_lossy().as_ref(), - store_file_identity, - body_route_envelope_sha256, - body_binding_sha256, - ))?); - Ok(format!("workspace-coverage:{digest:x}")) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - BODY_SCHEMA_VERSION, EpiphanyMindIdentity, EpiphanyRuntimeIdentity, - EpiphanyRuntimeSwarmBinding, MIND_SCHEMA_EPOCH, RUNTIME_IDENTITY_KEY, - RUNTIME_IDENTITY_TYPE, RUNTIME_SPINE_SCHEMA_VERSION, RUNTIME_SWARM_BINDING_KEY, - RUNTIME_SWARM_BINDING_SCHEMA_VERSION, - }; - use std::collections::BTreeMap; - - const NOW: &str = "2026-07-17T08:00:00Z"; - - struct Fixture { - _temp: tempfile::TempDir, - runtime_store: PathBuf, - worktree: PathBuf, - projection_store: PathBuf, - } - - fn fixture() -> Result { - let temp = tempfile::tempdir()?; - let worktree = temp.path().join("repo"); - let state = temp.path().join("state"); - std::fs::create_dir_all(&worktree)?; - std::fs::create_dir_all(&state)?; - let worktree = std::fs::canonicalize(worktree)?; - let state = std::fs::canonicalize(state)?; - let runtime_store = state.join("runtime.cc"); - let body_store = state.join("body.cc"); - let projection_store = state.join("workspace-coverage.cc"); - let body = RepositoryBodyBinding { - schema_version: BODY_SCHEMA_VERSION.into(), - workspace_id: "workspace-1".into(), - swarm_id: "swarm-1".into(), - runtime_id: "runtime-1".into(), - scope: "git_worktree".into(), - source_identity_type: crate::RUNTIME_IDENTITY_TYPE.into(), - source_identity_key: crate::RUNTIME_IDENTITY_KEY.into(), - source_identity_sha256: "a".repeat(64), - git_top_level: worktree.to_string_lossy().into_owned(), - object_format: "sha1".into(), - global_excludes_policy: "disabled_for_observation".into(), - }; - let body_digest = format!("{:x}", Sha256::digest(rmp_serde::to_vec_named(&body)?)); - let mut body_backing = SingleFileMessagePackBackingStore::new(&body_store); - body_backing.push(&envelope(BODY_BINDING_TYPE, BODY_BINDING_KEY, &body, NOW)?)?; - let body_store = std::fs::canonicalize(body_store)?; - - let identity = EpiphanyRuntimeIdentity { - schema_version: RUNTIME_SPINE_SCHEMA_VERSION.into(), - runtime_id: "runtime-1".into(), - display_name: "test".into(), - runtime_kind: "epiphany.native".into(), - created_at: NOW.into(), - updated_at: NOW.into(), - supported_document_types: Vec::new(), - metadata: BTreeMap::new(), - }; - let swarm = EpiphanyRuntimeSwarmBinding { - schema_version: RUNTIME_SWARM_BINDING_SCHEMA_VERSION.into(), - binding_id: RUNTIME_SWARM_BINDING_KEY.into(), - runtime_id: "runtime-1".into(), - swarm_id: "swarm-1".into(), - source_identity_type: body.source_identity_type.clone(), - source_identity_key: body.source_identity_key.clone(), - source_identity_sha256: body.source_identity_sha256.clone(), - bound_at: NOW.into(), - }; - let route = RuntimeRepositoryBodyStoreBinding { - schema_version: BODY_SCHEMA_VERSION.into(), - binding_id: RUNTIME_BODY_STORE_BINDING_KEY.into(), - runtime_id: "runtime-1".into(), - swarm_id: "swarm-1".into(), - workspace_id: "workspace-1".into(), - body_store_path: body_store.to_string_lossy().into_owned(), - body_binding_sha256: body_digest, - }; - let mut runtime_backing = SingleFileMessagePackBackingStore::new(&runtime_store); - runtime_backing.push_all( - &[ - envelope(RUNTIME_IDENTITY_TYPE, RUNTIME_IDENTITY_KEY, &identity, NOW)?, - envelope( - EpiphanyMindIdentity::TYPE, - MIND_SCHEMA_EPOCH, - &EpiphanyMindIdentity { - schema_epoch: MIND_SCHEMA_EPOCH.into(), - runtime_id: identity.runtime_id.clone(), - }, - NOW, - )?, - envelope( - EpiphanyRuntimeSwarmBinding::TYPE, - RUNTIME_SWARM_BINDING_KEY, - &swarm, - NOW, - )?, - envelope( - RUNTIME_BODY_STORE_BINDING_TYPE, - RUNTIME_BODY_STORE_BINDING_KEY, - &route, - NOW, - )?, - ], - Default::default(), - )?; - Ok(Fixture { - _temp: temp, - runtime_store, - worktree, - projection_store, - }) - } - - #[test] - fn bind_once_and_reopen_return_the_same_validated_authority() -> Result<()> { - let fixture = fixture()?; - let bound = bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - NOW, - )?; - let reopened = open_workspace_coverage_authority(&fixture.runtime_store)?; - assert_eq!(reopened.runtime_coverage_route, bound); - assert_eq!(reopened.store_binding.created_at_utc, bound.created_at_utc); - assert_eq!(reopened.runtime_body_route.workspace_id, "workspace-1"); - assert_eq!(reopened.body_binding.workspace_id, "workspace-1"); - assert_eq!(reopened.store.pull_all()?.len(), 1); - drop(reopened); - let rebound = bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - "2026-07-17T09:00:00Z", - )?; - assert_eq!(rebound, bound); - Ok(()) - } - - #[cfg(windows)] - #[test] - fn ordinary_windows_spelling_binds_and_rebinds_the_canonical_store() -> Result<()> { - let fixture = fixture()?; - let canonical = fixture.projection_store.clone(); - let ordinary = PathBuf::from( - canonical - .to_string_lossy() - .strip_prefix(r"\\?\") - .expect("Windows canonical test path should use extended-length spelling"), - ); - - let bound = bind_runtime_workspace_coverage_store(&fixture.runtime_store, &ordinary, NOW)?; - assert_eq!(PathBuf::from(&bound.projection_store_path), canonical); - assert_eq!( - bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &ordinary, - "2026-07-17T09:00:00Z", - )?, - bound - ); - assert_eq!( - open_workspace_coverage_authority(&fixture.runtime_store)?.runtime_coverage_route, - bound - ); - Ok(()) - } - - #[test] - fn interrupted_first_bind_retry_adopts_valid_local_timestamp_and_binding_id() -> Result<()> { - let fixture = fixture()?; - let first = bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - NOW, - )?; - let mut runtime = SingleFileMessagePackBackingStore::new(&fixture.runtime_store); - let route_envelope = runtime - .pull_all()? - .into_iter() - .find(|entry| { - entry.r#type == RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_TYPE - && entry.key == RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY - }) - .unwrap(); - runtime.delete(&route_envelope)?; - - let recovered = bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - "2026-07-17T09:00:00Z", - )?; - assert_eq!(recovered.binding_id, first.binding_id); - assert_eq!(recovered.created_at_utc, NOW); - assert_ne!( - recovered.binding_id, - RUNTIME_WORKSPACE_COVERAGE_STORE_BINDING_KEY - ); - assert_ne!(recovered.binding_id, WORKSPACE_COVERAGE_STORE_BINDING_KEY); - Ok(()) - } - - #[test] - fn live_authority_does_not_block_route_lookup_or_idempotent_bind() -> Result<()> { - let fixture = fixture()?; - let bound = bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - NOW, - )?; - let authority = open_workspace_coverage_authority(&fixture.runtime_store)?; - assert_eq!( - runtime_workspace_coverage_store_binding(&fixture.runtime_store)?, - Some(bound.clone()) - ); - assert_eq!( - bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - "2026-07-17T09:00:00Z", - )?, - bound - ); - assert!(open_workspace_coverage_authority(&fixture.runtime_store).is_err()); - authority.store.validate_path_identity()?; - Ok(()) - } - - #[test] - fn bind_once_refuses_destination_substitution_and_inside_worktree_path() -> Result<()> { - let first = fixture()?; - bind_runtime_workspace_coverage_store(&first.runtime_store, &first.projection_store, NOW)?; - let alternate = first.projection_store.with_file_name("alternate.cc"); - assert!( - bind_runtime_workspace_coverage_store(&first.runtime_store, alternate, NOW).is_err() - ); - - let second = fixture()?; - let inside = second.worktree.join("coverage.cc"); - assert!(bind_runtime_workspace_coverage_store(&second.runtime_store, inside, NOW).is_err()); - Ok(()) - } - - #[test] - fn open_refuses_exact_body_route_envelope_substitution() -> Result<()> { - let fixture = fixture()?; - bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - NOW, - )?; - let mut runtime = SingleFileMessagePackBackingStore::new(&fixture.runtime_store); - let route = runtime - .pull_all()? - .into_iter() - .find(|entry| { - entry.r#type == RUNTIME_BODY_STORE_BINDING_TYPE - && entry.key == RUNTIME_BODY_STORE_BINDING_KEY - }) - .unwrap(); - let mut substituted = route.clone(); - substituted.stored_at = "2026-07-17T08:00:01Z".into(); - runtime.push(&substituted)?; - assert!(open_workspace_coverage_authority(&fixture.runtime_store).is_err()); - Ok(()) - } - - #[test] - fn open_refuses_store_local_binding_mismatch() -> Result<()> { - let fixture = fixture()?; - bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - NOW, - )?; - let mut store = OwnedRedbMessagePackBackingStore::new(&fixture.projection_store)?; - let current = store.pull_all()?.into_iter().next().unwrap(); - let mut binding: WorkspaceCoverageStoreBinding = decode(¤t)?; - binding.workspace_id = "substituted".into(); - store.push(&envelope( - WORKSPACE_COVERAGE_STORE_BINDING_TYPE, - WORKSPACE_COVERAGE_STORE_BINDING_KEY, - &binding, - NOW, - )?)?; - drop(store); - assert_eq!( - open_workspace_coverage_authority(&fixture.runtime_store) - .unwrap_err() - .to_string(), - "workspace coverage store binding disagrees with runtime route" - ); - Ok(()) - } - - #[test] - fn opened_authority_stays_on_pinned_file_and_reopen_refuses_copied_replacement() -> Result<()> { - let fixture = fixture()?; - bind_runtime_workspace_coverage_store( - &fixture.runtime_store, - &fixture.projection_store, - NOW, - )?; - let copied = fixture - .projection_store - .with_file_name("workspace-coverage-copy.cc"); - std::fs::copy(&fixture.projection_store, &copied)?; - let mut authority = open_workspace_coverage_authority(&fixture.runtime_store)?; - let original_identity = authority.store.file_identity().to_string(); - let displaced = fixture - .projection_store - .with_file_name("workspace-coverage-displaced.cc"); - std::fs::rename(&fixture.projection_store, &displaced)?; - std::fs::rename(&copied, &fixture.projection_store)?; - assert!(authority.store.validate_path_identity().is_err()); - assert_eq!(authority.store.file_identity(), original_identity); - let pinned_entry = envelope("test.pinned", "after-replacement", &"still-original", NOW)?; - authority.store.push(&pinned_entry)?; - assert!( - authority - .store - .pull_all()? - .iter() - .any(|entry| entry.r#type == "test.pinned") - ); - drop(authority); - assert!(open_workspace_coverage_authority(&fixture.runtime_store).is_err()); - Ok(()) - } -} diff --git a/epiphany-core/src/workspace_retrieval_coverage.rs b/epiphany-core/src/workspace_retrieval_coverage.rs deleted file mode 100644 index d6f5d7eb..00000000 --- a/epiphany-core/src/workspace_retrieval_coverage.rs +++ /dev/null @@ -1,952 +0,0 @@ -use crate::{ - RepositoryBodyManifest, RepositoryBodyManifestEntry, RepositoryBodyObservationBasis, - authenticated_repository_body_manifest, -}; -use anyhow::{Result, anyhow, bail}; -use cultcache_rs::DatabaseEntry; -use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use std::path::Path; - -pub const WORKSPACE_COVERAGE_POLICY_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_policy.v0"; -pub const WORKSPACE_COVERAGE_OBLIGATION_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_obligation.v0"; -pub const WORKSPACE_COVERAGE_RECEIPT_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_receipt.v0"; -pub const WORKSPACE_COVERAGE_PROJECTION_PLAN_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_projection_plan.v0"; -pub const WORKSPACE_COVERAGE_HEAD_SCHEMA_VERSION: &str = - "gamecult.epiphany.workspace_coverage_head.v0"; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum WorkspaceCoverageDisposition { - IncludeRegularFile, - ExcludeGitlink, - ExcludeSymlink, - ExcludeUnsupportedKind, - ExcludeEmptyRegularFile, - ExcludeNonUtf8RegularFile, - ExcludeOversize, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct WorkspaceCoveragePolicy { - pub schema_version: String, - pub policy_id: String, - pub maximum_file_bytes: u64, -} - -impl WorkspaceCoveragePolicy { - pub fn bounded_regular_files_v0(maximum_file_bytes: u64) -> Result { - if maximum_file_bytes == 0 { - bail!("workspace coverage policy maximum_file_bytes must be positive"); - } - Ok(Self { - schema_version: WORKSPACE_COVERAGE_POLICY_SCHEMA_VERSION.into(), - policy_id: "bounded_regular_files_v0".into(), - maximum_file_bytes, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct WorkspaceCoverageClassification { - pub path: String, - pub raw_sha256: String, - pub raw_byte_length: u64, - pub disposition: WorkspaceCoverageDisposition, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_obligation", - schema = "WorkspaceCoverageObligation" -)] -pub(crate) struct WorkspaceCoverageObligation { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub obligation_id: String, - #[cultcache(key = 2)] - pub workspace_id: String, - #[cultcache(key = 3)] - pub swarm_id: String, - #[cultcache(key = 4)] - pub runtime_id: String, - #[cultcache(key = 5)] - pub body_binding_sha256: String, - #[cultcache(key = 6)] - pub body_observation_id: String, - #[cultcache(key = 7)] - pub body_generation: u64, - #[cultcache(key = 8)] - pub manifest_root_sha256: String, - #[cultcache(key = 9)] - pub policy_id: String, - #[cultcache(key = 10)] - pub policy_sha256: String, - #[cultcache(key = 11)] - pub classification_set_sha256: String, - #[cultcache(key = 12)] - pub classifications: Vec, - #[cultcache(key = 13)] - pub included_entry_count: u64, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct WorkspaceCoverageChunkDescriptor { - pub body_path: String, - pub source_raw_sha256: String, - pub source_raw_byte_length: u64, - pub chunk_index: u32, - pub byte_start: u64, - pub byte_end: u64, - pub chunk_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct WorkspaceCoveragePlannedPoint { - pub point_id: String, - pub body_path: String, - pub source_raw_sha256: String, - pub source_raw_byte_length: u64, - pub chunk_index: u32, - pub byte_start: u64, - pub byte_end: u64, - pub chunk_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct WorkspaceCoveragePointPayload { - pub obligation_id: String, - pub projection_schema_version: String, - pub chunker_id: String, - pub body_path: String, - pub source_raw_sha256: String, - pub source_raw_byte_length: u64, - pub chunk_index: u32, - pub byte_start: u64, - pub byte_end: u64, - pub chunk_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct WorkspaceCoveragePointBinding { - pub point_id: String, - pub payload_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct WorkspaceCoverageVectorBinding { - pub point_id: String, - pub vector_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_projection_plan", - schema = "WorkspaceCoverageProjectionPlan" -)] -pub(crate) struct WorkspaceCoverageProjectionPlan { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub plan_id: String, - #[cultcache(key = 2)] - pub obligation_id: String, - #[cultcache(key = 3)] - pub projection_schema_version: String, - #[cultcache(key = 4)] - pub chunker_id: String, - #[cultcache(key = 5)] - pub embedding_provider_id: String, - #[cultcache(key = 6)] - pub embedding_model: String, - #[cultcache(key = 7)] - pub vector_dimensions: u32, - #[cultcache(key = 8)] - pub planned_points: Vec, - #[cultcache(key = 9)] - pub expected_point_count: u64, - #[cultcache(key = 10)] - pub expected_point_set_sha256: String, - #[cultcache(key = 11)] - pub point_bindings: Vec, - #[cultcache(key = 12)] - pub point_binding_set_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_receipt", - schema = "WorkspaceCoverageReceipt" -)] -pub(crate) struct WorkspaceCoverageReceipt { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub receipt_id: String, - #[cultcache(key = 2)] - pub obligation_id: String, - #[cultcache(key = 3)] - pub plan_id: String, - #[cultcache(key = 4)] - pub collection_name: String, - #[cultcache(key = 5)] - pub embedding_provider_id: String, - #[cultcache(key = 6)] - pub embedding_model: String, - #[cultcache(key = 7)] - pub vector_dimensions: u32, - #[cultcache(key = 8)] - pub observed_point_count: u64, - #[cultcache(key = 9)] - pub observed_point_set_sha256: String, - #[cultcache(key = 10)] - pub observed_at: String, - #[cultcache(key = 11)] - pub observation_method: String, - #[cultcache(key = 12)] - pub observed_point_binding_set_sha256: String, - #[cultcache(key = 13)] - pub claim_id: String, - #[cultcache(key = 14)] - pub claim_epoch: u64, - #[cultcache(key = 15)] - pub observed_vector_binding_set_sha256: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] -#[cultcache( - type = "gamecult.epiphany.workspace_coverage_head", - schema = "WorkspaceCoverageHead" -)] -pub(crate) struct WorkspaceCoverageHead { - #[cultcache(key = 0)] - pub schema_version: String, - #[cultcache(key = 1)] - pub workspace_id: String, - #[cultcache(key = 2)] - pub obligation_id: String, - #[cultcache(key = 3)] - pub plan_id: String, - #[cultcache(key = 4)] - pub receipt_id: String, - #[cultcache(key = 5)] - pub body_observation_id: String, - #[cultcache(key = 6)] - pub body_generation: u64, - #[cultcache(key = 7)] - pub manifest_root_sha256: String, - #[cultcache(key = 8)] - pub claim_id: String, - #[cultcache(key = 9)] - pub claim_epoch: u64, -} - -pub(crate) fn derive_workspace_coverage_obligation( - runtime_store: &Path, - basis: &RepositoryBodyObservationBasis, - policy: &WorkspaceCoveragePolicy, -) -> Result { - let manifest = authenticated_repository_body_manifest(runtime_store, basis)?; - derive_workspace_coverage_obligation_from_authenticated_manifest(basis, &manifest, policy) -} - -pub(crate) fn derive_workspace_coverage_obligation_from_authenticated_manifest( - basis: &RepositoryBodyObservationBasis, - manifest: &RepositoryBodyManifest, - policy: &WorkspaceCoveragePolicy, -) -> Result { - if policy.schema_version != WORKSPACE_COVERAGE_POLICY_SCHEMA_VERSION - || policy.policy_id.trim().is_empty() - || policy.maximum_file_bytes == 0 - { - bail!("unsupported or invalid workspace coverage policy"); - } - if manifest.workspace_id != basis.workspace_id - || manifest.scope != basis.scope - || manifest.manifest_root_sha256 != basis.manifest_root_sha256 - || basis.generation == 0 - { - bail!("workspace coverage input manifest disagrees with authenticated Body basis"); - } - let mut prior_path: Option<&str> = None; - let mut classifications = Vec::with_capacity(manifest.entries.len()); - for entry in &manifest.entries { - if entry.path.trim().is_empty() - || (entry.raw_sha256.trim().is_empty() && entry.kind != "gitlink_nonrecursive") - || prior_path.is_some_and(|prior| prior >= entry.path.as_str()) - { - bail!("Body manifest entries must have unique, strictly ordered paths and hashes"); - } - prior_path = Some(&entry.path); - classifications.push(classify(entry, policy)); - } - let policy_sha256 = digest(policy)?; - let classification_set_sha256 = digest(&classifications)?; - let included_entry_count = classifications - .iter() - .filter(|entry| entry.disposition == WorkspaceCoverageDisposition::IncludeRegularFile) - .count() as u64; - let obligation_id = format!( - "workspace-coverage:{}", - digest(&( - &basis.body_binding_sha256, - &basis.observation_id, - &basis.manifest_root_sha256, - &policy_sha256, - &classification_set_sha256, - ))? - ); - Ok(WorkspaceCoverageObligation { - schema_version: WORKSPACE_COVERAGE_OBLIGATION_SCHEMA_VERSION.into(), - obligation_id, - workspace_id: basis.workspace_id.clone(), - swarm_id: basis.swarm_id.clone(), - runtime_id: basis.runtime_id.clone(), - body_binding_sha256: basis.body_binding_sha256.clone(), - body_observation_id: basis.observation_id.clone(), - body_generation: basis.generation, - manifest_root_sha256: basis.manifest_root_sha256.clone(), - policy_id: policy.policy_id.clone(), - policy_sha256, - classification_set_sha256, - classifications, - included_entry_count, - }) -} - -pub(crate) fn refine_workspace_coverage_obligation_utf8( - obligation: &WorkspaceCoverageObligation, - non_utf8_paths: &[String], -) -> Result { - if !non_utf8_paths.windows(2).all(|pair| pair[0] < pair[1]) { - bail!("non-UTF-8 Body paths must be unique and canonically ordered"); - } - let mut refined = obligation.clone(); - for path in non_utf8_paths { - let classification = refined - .classifications - .iter_mut() - .find(|entry| &entry.path == path) - .ok_or_else(|| anyhow!("non-UTF-8 path is absent from Body obligation"))?; - if classification.disposition != WorkspaceCoverageDisposition::IncludeRegularFile { - bail!("non-UTF-8 refinement may only demote an included regular file"); - } - classification.disposition = WorkspaceCoverageDisposition::ExcludeNonUtf8RegularFile; - } - refined.included_entry_count = refined - .classifications - .iter() - .filter(|entry| entry.disposition == WorkspaceCoverageDisposition::IncludeRegularFile) - .count() as u64; - refined.classification_set_sha256 = digest(&refined.classifications)?; - refined.obligation_id = format!( - "workspace-coverage:{}", - digest(&( - &refined.body_binding_sha256, - &refined.body_observation_id, - &refined.manifest_root_sha256, - &refined.policy_sha256, - &refined.classification_set_sha256, - ))? - ); - Ok(refined) -} - -#[allow(clippy::too_many_arguments)] -pub(crate) fn derive_workspace_coverage_projection_plan( - obligation: &WorkspaceCoverageObligation, - projection_schema_version: &str, - chunker_id: &str, - embedding_provider_id: &str, - embedding_model: &str, - vector_dimensions: u32, - chunk_descriptors: Vec, -) -> Result { - if obligation.schema_version != WORKSPACE_COVERAGE_OBLIGATION_SCHEMA_VERSION - || projection_schema_version.trim().is_empty() - || chunker_id.trim().is_empty() - || embedding_provider_id.trim().is_empty() - || embedding_model.trim().is_empty() - || vector_dimensions == 0 - || (obligation.included_entry_count == 0) != chunk_descriptors.is_empty() - { - bail!("workspace coverage projection plan is incomplete or noncanonical"); - } - let included = obligation - .classifications - .iter() - .filter(|entry| entry.disposition == WorkspaceCoverageDisposition::IncludeRegularFile) - .map(|entry| (entry.path.as_str(), entry)) - .collect::>(); - let mut planned_points = Vec::with_capacity(chunk_descriptors.len()); - let mut prior_descriptor: Option<(String, u32)> = None; - for descriptor in chunk_descriptors { - let Some(source) = included.get(descriptor.body_path.as_str()) else { - bail!("workspace coverage chunk does not name an included Body entry"); - }; - let valid_range = descriptor.byte_start < descriptor.byte_end - && descriptor.byte_end <= descriptor.source_raw_byte_length; - if descriptor.source_raw_sha256 != source.raw_sha256 - || descriptor.source_raw_byte_length != source.raw_byte_length - || !sha256_hex(&descriptor.source_raw_sha256) - || !sha256_hex(&descriptor.chunk_sha256) - || !valid_range - || (prior_descriptor.is_none() && descriptor.chunk_index != 0) - || prior_descriptor.as_ref().is_some_and(|prior| { - if prior.0 == descriptor.body_path { - prior.1.checked_add(1) != Some(descriptor.chunk_index) - } else { - descriptor.body_path <= prior.0 || descriptor.chunk_index != 0 - } - }) - { - bail!("workspace coverage chunk descriptor disagrees with Body or canonical order"); - } - prior_descriptor = Some((descriptor.body_path.clone(), descriptor.chunk_index)); - let point_id = uuid::Uuid::new_v5( - &uuid::Uuid::NAMESPACE_URL, - rmp_serde::to_vec_named(&( - &obligation.obligation_id, - projection_schema_version, - chunker_id, - &descriptor, - ))? - .as_slice(), - ) - .to_string(); - planned_points.push(WorkspaceCoveragePlannedPoint { - point_id, - body_path: descriptor.body_path, - source_raw_sha256: descriptor.source_raw_sha256, - source_raw_byte_length: descriptor.source_raw_byte_length, - chunk_index: descriptor.chunk_index, - byte_start: descriptor.byte_start, - byte_end: descriptor.byte_end, - chunk_sha256: descriptor.chunk_sha256, - }); - } - if included.values().any(|entry| { - !planned_points - .iter() - .any(|point| point.body_path == entry.path) - }) { - bail!("workspace coverage plan omits an included Body entry"); - } - let mut point_ids = planned_points - .iter() - .map(|point| point.point_id.clone()) - .collect::>(); - point_ids.sort(); - let mut point_bindings = planned_points - .iter() - .map(|point| { - let payload = point_payload(obligation, projection_schema_version, chunker_id, point); - Ok(WorkspaceCoveragePointBinding { - point_id: point.point_id.clone(), - payload_sha256: digest(&payload)?, - }) - }) - .collect::>>()?; - point_bindings.sort_by(|left, right| left.point_id.cmp(&right.point_id)); - let expected_point_count = point_ids.len() as u64; - let expected_point_set_sha256 = digest(&point_ids)?; - let point_binding_set_sha256 = digest(&point_bindings)?; - let identity = ( - &obligation.obligation_id, - projection_schema_version, - chunker_id, - embedding_provider_id, - embedding_model, - vector_dimensions, - &planned_points, - &expected_point_set_sha256, - &point_bindings, - &point_binding_set_sha256, - ); - let plan_id = format!("workspace-coverage-plan:{}", digest(&identity)?); - Ok(WorkspaceCoverageProjectionPlan { - schema_version: WORKSPACE_COVERAGE_PROJECTION_PLAN_SCHEMA_VERSION.into(), - plan_id, - obligation_id: obligation.obligation_id.clone(), - projection_schema_version: projection_schema_version.into(), - chunker_id: chunker_id.into(), - embedding_provider_id: embedding_provider_id.into(), - embedding_model: embedding_model.into(), - vector_dimensions, - planned_points, - expected_point_count, - expected_point_set_sha256, - point_bindings, - point_binding_set_sha256, - }) -} - -pub(crate) fn validate_workspace_coverage_projection_plan( - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, -) -> Result<()> { - let expected = derive_workspace_coverage_projection_plan( - obligation, - &plan.projection_schema_version, - &plan.chunker_id, - &plan.embedding_provider_id, - &plan.embedding_model, - plan.vector_dimensions, - plan.planned_points - .iter() - .map(|point| WorkspaceCoverageChunkDescriptor { - body_path: point.body_path.clone(), - source_raw_sha256: point.source_raw_sha256.clone(), - source_raw_byte_length: point.source_raw_byte_length, - chunk_index: point.chunk_index, - byte_start: point.byte_start, - byte_end: point.byte_end, - chunk_sha256: point.chunk_sha256.clone(), - }) - .collect(), - )?; - if *plan != expected { - bail!("workspace coverage projection plan identity or derived fields were altered"); - } - Ok(()) -} - -pub(crate) fn validate_workspace_coverage_receipt( - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, - receipt: &WorkspaceCoverageReceipt, -) -> Result<()> { - validate_workspace_coverage_projection_plan(obligation, plan)?; - let expected_collection = workspace_coverage_execution_collection( - &plan.plan_id, - &receipt.claim_id, - receipt.claim_epoch, - )?; - if receipt.schema_version != WORKSPACE_COVERAGE_RECEIPT_SCHEMA_VERSION - || receipt.obligation_id != obligation.obligation_id - || receipt.plan_id != plan.plan_id - || receipt.receipt_id.trim().is_empty() - || receipt.collection_name != expected_collection - || receipt.embedding_provider_id != plan.embedding_provider_id - || receipt.embedding_model != plan.embedding_model - || receipt.vector_dimensions != plan.vector_dimensions - || receipt.observed_at.trim().is_empty() - || receipt.observation_method != "qdrant_scroll_exact_point_bindings" - || !sha256_hex(&receipt.observed_vector_binding_set_sha256) - { - bail!("workspace coverage receipt lacks exact observed-index authority"); - } - if receipt.observed_point_count != plan.expected_point_count - || receipt.observed_point_set_sha256 != plan.expected_point_set_sha256 - || receipt.observed_point_binding_set_sha256 != plan.point_binding_set_sha256 - { - bail!("workspace coverage receipt does not prove the exact expected point set"); - } - Ok(()) -} - -pub(crate) fn validate_workspace_coverage_head( - obligation: &WorkspaceCoverageObligation, - plan: &WorkspaceCoverageProjectionPlan, - receipt: &WorkspaceCoverageReceipt, - head: &WorkspaceCoverageHead, -) -> Result<()> { - validate_workspace_coverage_receipt(obligation, plan, receipt)?; - if head.schema_version != WORKSPACE_COVERAGE_HEAD_SCHEMA_VERSION - || head.workspace_id != obligation.workspace_id - || head.obligation_id != obligation.obligation_id - || head.plan_id != plan.plan_id - || head.receipt_id != receipt.receipt_id - || receipt.obligation_id != obligation.obligation_id - || receipt.plan_id != plan.plan_id - || head.body_observation_id != obligation.body_observation_id - || head.body_generation != obligation.body_generation - || head.manifest_root_sha256 != obligation.manifest_root_sha256 - || head.claim_id != receipt.claim_id - || head.claim_epoch != receipt.claim_epoch - { - bail!("workspace coverage head does not join one obligation to its exact receipt"); - } - Ok(()) -} - -pub fn workspace_coverage_execution_collection( - plan_id: &str, - claim_id: &str, - claim_epoch: u64, -) -> Result { - if plan_id.trim().is_empty() || uuid::Uuid::parse_str(claim_id).is_err() || claim_epoch == 0 { - bail!("workspace coverage execution collection requires plan and fenced UUID claim"); - } - let namespace = digest(&(plan_id, claim_id, claim_epoch))?; - Ok(format!("epiphany_workspace_{}", &namespace[..40])) -} - -fn point_payload( - obligation: &WorkspaceCoverageObligation, - projection_schema_version: &str, - chunker_id: &str, - point: &WorkspaceCoveragePlannedPoint, -) -> WorkspaceCoveragePointPayload { - WorkspaceCoveragePointPayload { - obligation_id: obligation.obligation_id.clone(), - projection_schema_version: projection_schema_version.into(), - chunker_id: chunker_id.into(), - body_path: point.body_path.clone(), - source_raw_sha256: point.source_raw_sha256.clone(), - source_raw_byte_length: point.source_raw_byte_length, - chunk_index: point.chunk_index, - byte_start: point.byte_start, - byte_end: point.byte_end, - chunk_sha256: point.chunk_sha256.clone(), - } -} - -fn sha256_hex(value: &str) -> bool { - value.len() == 64 - && value - .bytes() - .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) -} - -fn classify( - entry: &RepositoryBodyManifestEntry, - policy: &WorkspaceCoveragePolicy, -) -> WorkspaceCoverageClassification { - let disposition = match entry.kind.as_str() { - "gitlink_nonrecursive" => WorkspaceCoverageDisposition::ExcludeGitlink, - "symlink_target" => WorkspaceCoverageDisposition::ExcludeSymlink, - "regular" if entry.raw_byte_length == 0 => { - WorkspaceCoverageDisposition::ExcludeEmptyRegularFile - } - "regular" if entry.raw_byte_length > policy.maximum_file_bytes => { - WorkspaceCoverageDisposition::ExcludeOversize - } - "regular" => WorkspaceCoverageDisposition::IncludeRegularFile, - _ => WorkspaceCoverageDisposition::ExcludeUnsupportedKind, - }; - WorkspaceCoverageClassification { - path: entry.path.clone(), - raw_sha256: entry.raw_sha256.clone(), - raw_byte_length: entry.raw_byte_length, - disposition, - } -} - -fn digest(value: &(impl Serialize + ?Sized)) -> Result { - Ok(format!( - "{:x}", - Sha256::digest(rmp_serde::to_vec_named(value).map_err(|error| anyhow!(error))?) - )) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn basis() -> RepositoryBodyObservationBasis { - RepositoryBodyObservationBasis { - schema_version: "epiphany.repository_body.v2".into(), - workspace_id: "workspace-1".into(), - swarm_id: "swarm-1".into(), - runtime_id: "runtime-1".into(), - scope: "git_worktree".into(), - body_binding_sha256: "binding-hash".into(), - observation_id: "workspace-1:7".into(), - generation: 7, - manifest_root_sha256: "manifest-hash".into(), - scan_started_at: "start".into(), - scan_finished_at: "finish".into(), - } - } - - fn entry(path: &str, kind: &str, size: u64) -> RepositoryBodyManifestEntry { - RepositoryBodyManifestEntry { - path: path.into(), - git_mode: "100644".into(), - kind: kind.into(), - raw_byte_length: size, - raw_sha256: format!("hash-{path}"), - gitlink_oid: None, - } - } - - #[test] - fn every_manifest_entry_receives_one_policy_disposition() -> Result<()> { - let manifest = RepositoryBodyManifest { - schema_version: "epiphany.repository_body.v2".into(), - manifest_root_sha256: "manifest-hash".into(), - workspace_id: "workspace-1".into(), - scope: "git_worktree".into(), - entries: vec![ - entry("a-empty", "regular", 0), - entry("a.rs", "regular", 12), - entry("b.bin", "regular", 101), - entry("c-link", "symlink_target", 3), - entry("d-submodule", "gitlink_nonrecursive", 0), - ], - }; - let obligation = derive_workspace_coverage_obligation_from_authenticated_manifest( - &basis(), - &manifest, - &WorkspaceCoveragePolicy::bounded_regular_files_v0(100)?, - )?; - assert_eq!(obligation.classifications.len(), manifest.entries.len()); - assert_eq!(obligation.included_entry_count, 1); - assert_eq!( - obligation.classifications[0].disposition, - WorkspaceCoverageDisposition::ExcludeEmptyRegularFile - ); - assert_eq!( - obligation.classifications[2].disposition, - WorkspaceCoverageDisposition::ExcludeOversize - ); - Ok(()) - } - - #[test] - fn manifest_substitution_and_duplicate_paths_are_refused() -> Result<()> { - let mut manifest = RepositoryBodyManifest { - schema_version: "epiphany.repository_body.v2".into(), - manifest_root_sha256: "wrong".into(), - workspace_id: "workspace-1".into(), - scope: "git_worktree".into(), - entries: vec![entry("a", "regular", 1)], - }; - let policy = WorkspaceCoveragePolicy::bounded_regular_files_v0(100)?; - assert!( - derive_workspace_coverage_obligation_from_authenticated_manifest( - &basis(), - &manifest, - &policy - ) - .is_err() - ); - manifest.manifest_root_sha256 = "manifest-hash".into(); - manifest.entries.push(entry("a", "regular", 1)); - assert!( - derive_workspace_coverage_obligation_from_authenticated_manifest( - &basis(), - &manifest, - &policy - ) - .is_err() - ); - Ok(()) - } - - fn coverage_obligation(id: &str) -> WorkspaceCoverageObligation { - WorkspaceCoverageObligation { - schema_version: WORKSPACE_COVERAGE_OBLIGATION_SCHEMA_VERSION.into(), - obligation_id: id.into(), - workspace_id: "workspace-1".into(), - swarm_id: "swarm-1".into(), - runtime_id: "runtime-1".into(), - body_binding_sha256: "binding".into(), - body_observation_id: "workspace-1:1".into(), - body_generation: 1, - manifest_root_sha256: "manifest".into(), - policy_id: "bounded_regular_files_v0".into(), - policy_sha256: "policy".into(), - classification_set_sha256: "classes".into(), - classifications: vec![WorkspaceCoverageClassification { - path: "src/lib.rs".into(), - raw_sha256: "11".repeat(32), - raw_byte_length: 10, - disposition: WorkspaceCoverageDisposition::IncludeRegularFile, - }], - included_entry_count: 1, - } - } - - fn chunks() -> Vec { - vec![ - WorkspaceCoverageChunkDescriptor { - body_path: "src/lib.rs".into(), - source_raw_sha256: "11".repeat(32), - source_raw_byte_length: 10, - chunk_index: 0, - byte_start: 0, - byte_end: 5, - chunk_sha256: "22".repeat(32), - }, - WorkspaceCoverageChunkDescriptor { - body_path: "src/lib.rs".into(), - source_raw_sha256: "11".repeat(32), - source_raw_byte_length: 10, - chunk_index: 1, - byte_start: 3, - byte_end: 10, - chunk_sha256: "33".repeat(32), - }, - ] - } - - fn plan(obligation: &WorkspaceCoverageObligation) -> Result { - derive_workspace_coverage_projection_plan( - obligation, - "projection-v0", - "chunker-v0", - "provider", - "model", - 3, - chunks(), - ) - } - - #[test] - fn immutable_model_artifact_identity_changes_projection_plan() -> Result<()> { - let obligation = coverage_obligation("obligation-model-artifact"); - let first = derive_workspace_coverage_projection_plan( - &obligation, - "projection-v0", - "chunker-v0", - "provider", - &format!("model:latest@sha256:{}", "aa".repeat(32)), - 3, - chunks(), - )?; - let second = derive_workspace_coverage_projection_plan( - &obligation, - "projection-v0", - "chunker-v0", - "provider", - &format!("model:latest@sha256:{}", "bb".repeat(32)), - 3, - chunks(), - )?; - assert_ne!(first.plan_id, second.plan_id); - Ok(()) - } - - #[test] - fn receipt_and_head_cannot_substitute_payload_or_claim_authority() -> Result<()> { - let obligation = coverage_obligation("obligation-1"); - let plan = derive_workspace_coverage_projection_plan( - &obligation, - "projection-v0", - "chunker-v0", - "provider", - "model", - 3, - chunks(), - )?; - let claim_id = uuid::Uuid::new_v4().to_string(); - let claim_epoch = 7; - let mut receipt = WorkspaceCoverageReceipt { - schema_version: WORKSPACE_COVERAGE_RECEIPT_SCHEMA_VERSION.into(), - receipt_id: "receipt-1".into(), - obligation_id: obligation.obligation_id.clone(), - plan_id: plan.plan_id.clone(), - collection_name: workspace_coverage_execution_collection( - &plan.plan_id, - &claim_id, - claim_epoch, - )?, - embedding_provider_id: "provider".into(), - embedding_model: "model".into(), - vector_dimensions: 3, - observed_point_count: plan.expected_point_count, - observed_point_set_sha256: plan.expected_point_set_sha256.clone(), - observed_at: "now".into(), - observation_method: "qdrant_scroll_exact_point_bindings".into(), - observed_point_binding_set_sha256: plan.point_binding_set_sha256.clone(), - claim_id: claim_id.clone(), - claim_epoch, - observed_vector_binding_set_sha256: "55".repeat(32), - }; - assert!(validate_workspace_coverage_receipt(&obligation, &plan, &receipt).is_ok()); - let mut head = WorkspaceCoverageHead { - schema_version: WORKSPACE_COVERAGE_HEAD_SCHEMA_VERSION.into(), - workspace_id: obligation.workspace_id.clone(), - obligation_id: obligation.obligation_id.clone(), - plan_id: plan.plan_id.clone(), - receipt_id: receipt.receipt_id.clone(), - body_observation_id: obligation.body_observation_id.clone(), - body_generation: obligation.body_generation, - manifest_root_sha256: obligation.manifest_root_sha256.clone(), - claim_id, - claim_epoch, - }; - assert!(validate_workspace_coverage_head(&obligation, &plan, &receipt, &head).is_ok()); - receipt.observed_point_binding_set_sha256 = "44".repeat(32); - assert!(validate_workspace_coverage_receipt(&obligation, &plan, &receipt).is_err()); - receipt.observed_point_binding_set_sha256 = plan.point_binding_set_sha256.clone(); - receipt.claim_epoch += 1; - assert!(validate_workspace_coverage_receipt(&obligation, &plan, &receipt).is_err()); - receipt.claim_epoch = claim_epoch; - receipt.claim_id = "not-a-uuid".into(); - assert!(validate_workspace_coverage_receipt(&obligation, &plan, &receipt).is_err()); - receipt.claim_id = head.claim_id.clone(); - head.claim_id = uuid::Uuid::new_v4().to_string(); - assert!(validate_workspace_coverage_head(&obligation, &plan, &receipt, &head).is_err()); - receipt.observation_method = "claimed_upsert_count".into(); - assert!(validate_workspace_coverage_head(&obligation, &plan, &receipt, &head).is_err()); - Ok(()) - } - - #[test] - fn projection_plan_seals_point_set_and_rejects_cross_obligation_use() -> Result<()> { - let mut obligation = coverage_obligation("obligation-a"); - let mut duplicate = chunks(); - duplicate[1].chunk_index = 0; - assert!( - derive_workspace_coverage_projection_plan( - &obligation, - "projection", - "chunker", - "provider", - "model", - 3, - duplicate - ) - .is_err() - ); - let mut invalid = chunks(); - invalid[0].byte_end = 11; - assert!( - derive_workspace_coverage_projection_plan( - &obligation, - "projection", - "chunker", - "provider", - "model", - 3, - invalid - ) - .is_err() - ); - let mut plan = plan(&obligation)?; - assert!(uuid::Uuid::parse_str(&plan.planned_points[0].point_id).is_ok()); - plan.planned_points[0].chunk_sha256 = "44".repeat(32); - assert!(validate_workspace_coverage_projection_plan(&obligation, &plan).is_err()); - obligation.obligation_id = "obligation-b".into(); - assert!(validate_workspace_coverage_projection_plan(&obligation, &plan).is_err()); - Ok(()) - } - - #[test] - fn execution_claim_fences_collection_without_changing_plan() -> Result<()> { - let obligation = coverage_obligation("body-policy-epoch-a"); - let first = plan(&obligation)?; - let claim_a = uuid::Uuid::new_v4().to_string(); - let claim_b = uuid::Uuid::new_v4().to_string(); - let collection_a = workspace_coverage_execution_collection(&first.plan_id, &claim_a, 1)?; - let collection_b = workspace_coverage_execution_collection(&first.plan_id, &claim_b, 2)?; - assert_ne!(collection_a, collection_b); - assert_eq!(first, plan(&obligation)?); - assert!(collection_a.starts_with("epiphany_workspace_")); - assert_eq!(collection_a.len(), "epiphany_workspace_".len() + 40); - Ok(()) - } -} diff --git a/epiphany-openai-runtime/src/bin/epiphany-persona-service.rs b/epiphany-openai-runtime/src/bin/epiphany-persona-service.rs index 794ac2b9..5250ee2a 100644 --- a/epiphany-openai-runtime/src/bin/epiphany-persona-service.rs +++ b/epiphany-openai-runtime/src/bin/epiphany-persona-service.rs @@ -213,7 +213,6 @@ fn ensure_persona_pass_input_admitted( timestamp: mention.queued_at.clone(), }) .collect::>(); - let semantic_recall = String::new(); let social_affordances = request .mentions .iter() @@ -242,7 +241,6 @@ fn ensure_persona_pass_input_admitted( let projector_input = PersonaProjectorInput { identity, memories: memories.clone(), - semantic_memory_recall: semantic_recall.clone(), pending_mentions: request.mentions.clone(), repo_activity, social_affordances, @@ -278,7 +276,6 @@ fn ensure_persona_pass_input_admitted( .iter() .map(|mention| mention.channel_id.clone()) .collect(), - dynamic_semantic_memory_recall: semantic_recall, observed_sources, admitted_at: request.reserved_at.clone(), }; @@ -421,7 +418,6 @@ mod tests { }, transcript: Vec::new(), allowed_channel_ids: vec!["aquarium".into()], - dynamic_semantic_memory_recall: String::new(), observed_sources: vec![provenance.clone()], admitted_at: "2026-08-18T03:00:01Z".into(), }; diff --git a/epiphany-openai-runtime/src/persona_executor.rs b/epiphany-openai-runtime/src/persona_executor.rs index 226443ec..88bb078c 100644 --- a/epiphany-openai-runtime/src/persona_executor.rs +++ b/epiphany-openai-runtime/src/persona_executor.rs @@ -31,7 +31,6 @@ pub struct PersonaModelExecutionPlan { projector_input: PersonaProjectorInput, transcript: Vec, allowed_channel_ids: Vec, - dynamic_semantic_memory_recall: String, source_documents: Vec, cultmesh_store: PathBuf, runtime_id: String, @@ -56,7 +55,6 @@ impl PersonaModelExecutionPlan { projector_input: document.projector_input, transcript: document.transcript, allowed_channel_ids: document.allowed_channel_ids, - dynamic_semantic_memory_recall: document.dynamic_semantic_memory_recall, source_documents: vec![source], cultmesh_store, runtime_id: runtime_id.into(), @@ -284,8 +282,6 @@ pub async fn execute_persona_model_turn_with_runner( identity: plan.projector_input.identity.clone(), persona_prompt: projector.output.clone(), persona_output: persona.output.clone(), - semantic_memory_recall: plan.projector_input.semantic_memory_recall.clone(), - dynamic_semantic_memory_recall: plan.dynamic_semantic_memory_recall.clone(), pending_mentions: plan.projector_input.pending_mentions.clone(), allowed_channel_ids: plan.allowed_channel_ids.clone(), }; @@ -532,7 +528,6 @@ fn validate_plan_source(store_path: &PathBuf, plan: &PersonaModelExecutionPlan) || document.projector_input != plan.projector_input || document.transcript != plan.transcript || document.allowed_channel_ids != plan.allowed_channel_ids - || document.dynamic_semantic_memory_recall != plan.dynamic_semantic_memory_recall { return Err(anyhow!( "Persona execution plan diverges from its admitted Mind input" @@ -813,7 +808,6 @@ mod tests { }, transcript: vec![], allowed_channel_ids, - dynamic_semantic_memory_recall: String::new(), observed_sources: vec![provenance.clone()], admitted_at: "2026-08-14T00:00:00Z".into(), }; diff --git a/epiphany-release-construction/src/lib.rs b/epiphany-release-construction/src/lib.rs index c52ed5c9..3b5a076f 100644 --- a/epiphany-release-construction/src/lib.rs +++ b/epiphany-release-construction/src/lib.rs @@ -82,17 +82,8 @@ pub struct PackageReleaseRequest<'a> { pub fn required_packaged_release_binaries(target_triple: &str) -> Vec<(&'static str, String)> { let file_name = |name: &str| target_binary_file_name(target_triple, name); vec![ - ("supervisor", file_name("epiphany-daemon-supervisor")), ("release-publisher", file_name("epiphany-release")), ("state-steward", file_name("epiphany-state")), - ( - "semantic-projector", - file_name("epiphany-memory-semantic-projector"), - ), - ( - "workspace-coverage-projector", - file_name("epiphany-workspace-coverage-projector"), - ), ("atlas-publisher", file_name("epiphany-atlas-publisher")), ( "model-entanglement-projector", @@ -102,7 +93,6 @@ pub fn required_packaged_release_binaries(target_triple: &str) -> Vec<(&'static "atlas-impact-ingress", file_name("epiphany-atlas-impact-ingress"), ), - ("semantic-query", file_name("epiphany-memory-semantic")), ("repository-body", file_name("epiphany-repository-body")), ("host-identity", file_name("epiphany-host-identity")), ("swarm", file_name("epiphany-swarm")), @@ -615,19 +605,13 @@ fn release_bundle_target_dir( fn required_release_build_target(role: &str) -> Result<(&'static str, &'static str)> { match role { - "supervisor" => Ok(("epiphany-core", "epiphany-daemon-supervisor")), "release-publisher" => Ok(("epiphany-core", "epiphany-release")), "state-steward" => Ok(("epiphany-core", "epiphany-state")), - "semantic-projector" => Ok(("epiphany-core", "epiphany-memory-semantic-projector")), - "workspace-coverage-projector" => { - Ok(("epiphany-core", "epiphany-workspace-coverage-projector")) - } "atlas-publisher" => Ok(("epiphany-core", "epiphany-atlas-publisher")), "model-entanglement-projector" => { Ok(("epiphany-core", "epiphany-model-entanglement-projector")) } "atlas-impact-ingress" => Ok(("epiphany-core", "epiphany-atlas-impact-ingress")), - "semantic-query" => Ok(("epiphany-core", "epiphany-memory-semantic")), "repository-body" => Ok(("epiphany-core", "epiphany-repository-body")), "host-identity" => Ok(("epiphany-core", "epiphany-host-identity")), "swarm" => Ok(("epiphany-core", "epiphany-swarm")), diff --git a/epiphany-state-model/src/lib.rs b/epiphany-state-model/src/lib.rs index c16d9d01..81d0cdee 100644 --- a/epiphany-state-model/src/lib.rs +++ b/epiphany-state-model/src/lib.rs @@ -647,19 +647,7 @@ pub struct EpiphanyObjectiveDraftLanePlan { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] pub struct EpiphanyMemoryGraphSnapshot { - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "string | null")] - pub schema_version: Option, pub graph_id: String, - /// Monotonic identity of the canonical aggregate. Legacy snapshots decode as revision zero. - #[serde(default)] - pub model_revision: u64, - /// SHA-256 of the snapshot with this field cleared. - #[serde(default, skip_serializing_if = "String::is_empty")] - pub model_hash: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "EpiphanyMemoryGraphSource | null")] - pub source: Option, #[serde(default, skip_serializing_if = "Vec::is_empty")] #[ts(type = "Array")] pub domains: Vec, @@ -672,12 +660,6 @@ pub struct EpiphanyMemoryGraphSnapshot { #[serde(default, skip_serializing_if = "Vec::is_empty")] #[ts(type = "Array")] pub summaries: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "EpiphanyMemoryEmbeddingManifest | null")] - pub embedding_manifest: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "EpiphanyMemoryFreshness | null")] - pub freshness: Option, #[serde(default, skip_serializing_if = "Vec::is_empty")] #[ts(type = "Array")] pub lifecycle_receipts: Vec, @@ -794,7 +776,7 @@ pub fn reorient_checkpoint_from_admitted_repo_model( disposition: EpiphanyInvestigationDisposition::ResumeReady, focus: "Current Mind-admitted RepoModel frontier".to_string(), summary: Some( - "Derived from the authenticated current RepoModel semantic projection.".to_string(), + "Derived from the authenticated current keyed RepoModel view.".to_string(), ), next_action: Some("Resume from the current Mind-admitted RepoModel frontier.".to_string()), captured_at_turn_id: None, @@ -816,13 +798,6 @@ pub fn reorient_checkpoint_from_admitted_repo_model( } } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS)] -pub struct EpiphanyMemoryGraphSource { - pub kind: String, - pub identity: String, - pub revision: u64, -} - #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] pub struct EpiphanyMemoryDomain { pub id: String, @@ -1030,8 +1005,6 @@ pub struct EpiphanyMemorySummary { #[serde(default, skip_serializing_if = "Vec::is_empty")] #[ts(type = "Array")] pub source_hashes: Vec, - #[serde(default)] - pub freshness: EpiphanyMemoryFreshnessStatus, #[serde(default, skip_serializing_if = "is_zero_u32")] pub confidence: u32, #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -1058,133 +1031,7 @@ pub struct EpiphanyMemoryLifecycleReceipt { pub created_at: Option, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] -pub struct EpiphanyMemoryEmbeddingManifest { - pub id: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "string | null")] - pub collection_name: Option, - pub embedding_model: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "number | null")] - pub vector_dimensions: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub indexed_document_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub stale_document_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub source_hashes: Vec, -} -#[derive( - Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash, JsonSchema, TS, Default, -)] -#[serde(rename_all = "snake_case")] -#[ts(rename_all = "snake_case")] -pub enum EpiphanyMemoryFreshnessStatus { - #[default] - Missing, - Ready, - Stale, - Indexing, - Unavailable, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] -pub struct EpiphanyMemoryFreshness { - pub status: EpiphanyMemoryFreshnessStatus, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub stale_node_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub stale_edge_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub stale_summary_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub dirty_source_hashes: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "string | null")] - pub note: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] -pub struct EpiphanyMemoryContextQuery { - pub id: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "EpiphanyMemoryProfile | null")] - pub profile: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub domain_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub node_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub edge_ids: Vec, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "string | null")] - pub text: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(type = "number | null")] - pub budget: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] -pub struct EpiphanyMemoryContextPacket { - pub id: String, - pub query_id: String, - #[serde(default)] - pub repo_model_revision: u64, - #[serde(default, skip_serializing_if = "String::is_empty")] - pub repo_model_hash: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub nodes: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub edges: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub summaries: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub frontier: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub anchors: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub warnings: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub missing_node_ids: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub missing_edge_ids: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] -pub struct EpiphanyMemoryPatchCandidate { - pub id: String, - pub profile: EpiphanyMemoryProfile, - pub status: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub proposed_nodes: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub proposed_edges: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - #[ts(type = "Array")] - pub reasons: Vec, -} fn is_zero_u32(value: &u32) -> bool { *value == 0 diff --git a/state/void-memory.toml b/state/void-memory.toml deleted file mode 100644 index e8b7b1ca..00000000 --- a/state/void-memory.toml +++ /dev/null @@ -1,25 +0,0 @@ -schema_version = "epiphany.void_memory_bridge.v0" - -database_dsn_env = "VOID_DATABASE_DSN" -database_dsn = "postgres://voidbot:voidbot@localhost:5432/voidbot" - -qdrant_url = "http://127.0.0.1:6333" -qdrant_api_key_env = "QDRANT_API_KEY" -qdrant_history_collection = "voidbot_discord_history_chunks" -qdrant_source_collection = "voidbot_repository_source_chunks" -qdrant_timeout_ms = 30000 - -ollama_base_url = "http://127.0.0.1:11434" -ollama_model = "qwen3-embedding:0.6b" -ollama_timeout_ms = 30000 -history_query_instruction = "Given a Discord history question, retrieve relevant messages and discussion snippets that answer it." -source_query_instruction = "Given a source-tree, codebase, or lore question, retrieve relevant files, code snippets, and lore passages that answer it." - -archive_path = "E:\\Projects\\VoidBot\\.voidbot\\rag\\messages.json" - -policy = [ - "Persona may search archived Discord memory for context before speaking.", - "Qdrant is the semantic memory backend for Discord history and source/lore vectors.", - "Postgres is checked as the live Void state spine for jobs, audit, interaction memory, and rate limits.", - "Raw archive rows remain evidence, not public speech; Persona summarizes with restraint.", -]