diff --git a/crates/tracedecay-daemon-service/src/callable_code_authorization.rs b/crates/tracedecay-daemon-service/src/callable_code_authorization.rs index 1b8785788d..92431f7c66 100644 --- a/crates/tracedecay-daemon-service/src/callable_code_authorization.rs +++ b/crates/tracedecay-daemon-service/src/callable_code_authorization.rs @@ -1,5 +1,6 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::time::Duration; use tracedecay_contracts::{ ApplicationContractError, ApplicationOperation, ApplicationProblem, ApplicationProblemKind, @@ -7,12 +8,14 @@ use tracedecay_contracts::{ CallableCodeAuthorizationPort, RequestAdmission, RequestContext, ResolvedScope, RetryDirective, SafeDiagnostic, }; -use tracedecay_domain::{ComponentVersion, UtcMicros}; +use tracedecay_domain::{ActorId, ComponentVersion, UtcMicros}; use crate::callable_code_request_context; +use crate::project_owner_registration::project_owner_capabilities; +use tracedecay_application::project_open_authorization::ProjectOpenSourceAccessAuthorityV1; use tracedecay_application::{ CallableCodeAuthorizationSourcePort, CurrentCallableCodeAccessFuture, - ProjectSourceAccessSnapshot, + ProjectSourceAccessSnapshot, ProjectSourceAccessSnapshotPort, }; use tracedecay_configuration::config::PinnedRuntimeConfiguration; use tracedecay_configuration::{ @@ -23,6 +26,37 @@ use tracedecay_graph_query::CodeGraphReadError; type CurrentCallableCodeAccess = dyn Fn(UtcMicros) -> CurrentCallableCodeAccessFuture<'static> + Send + Sync; +const DAEMON_REQUESTER: &str = "actor.tracedecay-daemon.project-open"; +pub const GRANT_HORIZON: Duration = Duration::from_hours(24); + +pub fn project_open_source_access_authority() +-> Result { + let requester = ActorId::new(DAEMON_REQUESTER.to_owned()).map_err(|_| { + ApplicationContractError::Inconsistent { + field: "project-open requester", + } + })?; + Ok(ProjectOpenSourceAccessAuthorityV1::new( + requester, + project_owner_capabilities()?, + GRANT_HORIZON, + )) +} + +pub fn daemon_owned_project_source_access_at( + scope: &ResolvedScope, + project_root: &Path, + configuration: &PinnedRuntimeConfiguration, + observed_at: UtcMicros, +) -> Result { + project_open_source_access_authority()?.source_access_at( + scope, + project_root, + configuration, + observed_at, + ) +} + #[derive(Clone)] pub struct DaemonCallableCodeAuthorizationSource { access: Arc, @@ -41,25 +75,13 @@ impl DaemonCallableCodeAuthorizationSource { project_root: PathBuf, scope: ResolvedScope, configuration: Arc, - source_access_at: impl Fn( - &ResolvedScope, - &Path, - &PinnedRuntimeConfiguration, - UtcMicros, - ) - -> Result - + Send - + Sync - + 'static, ) -> Self { let project_root = Arc::new(project_root); let scope = Arc::new(scope); - let source_access_at = Arc::new(source_access_at); Self::new(move |observed_at| { let project_root = Arc::clone(&project_root); let scope = Arc::clone(&scope); let configuration = Arc::clone(&configuration); - let source_access_at = Arc::clone(&source_access_at); Box::pin(async move { let current = configuration .configuration_store() @@ -72,8 +94,13 @@ impl DaemonCallableCodeAuthorizationSource { current.snapshot, ) .map_err(|_| concealed())?; - source_access_at(&scope, &project_root, &configuration, observed_at) - .map_err(|_| concealed()) + daemon_owned_project_source_access_at( + &scope, + &project_root, + &configuration, + observed_at, + ) + .map_err(|_| concealed()) }) }) } @@ -124,25 +151,10 @@ impl DaemonCodeGraphReadAdmission { project_root: PathBuf, scope: ResolvedScope, configuration: Arc, - source_access_at: impl Fn( - &ResolvedScope, - &Path, - &PinnedRuntimeConfiguration, - UtcMicros, - ) - -> Result - + Send - + Sync - + 'static, ) -> Self { Self::new( scope.clone(), - DaemonCallableCodeAuthorizationSource::production( - project_root, - scope, - configuration, - source_access_at, - ), + DaemonCallableCodeAuthorizationSource::production(project_root, scope, configuration), ) } diff --git a/crates/tracedecay-daemon-service/src/lib.rs b/crates/tracedecay-daemon-service/src/lib.rs index bec74361a7..858af3a609 100644 --- a/crates/tracedecay-daemon-service/src/lib.rs +++ b/crates/tracedecay-daemon-service/src/lib.rs @@ -67,14 +67,15 @@ pub mod project_runtime; pub mod query_authority_provider; pub mod query_mcp_admission; pub mod remote_http_transport; -pub mod remote_protocol; +mod remote_protocol; pub mod request_cancellation; mod shutdown_coordination; mod multi_root; pub use callable_code_authorization::{ - DaemonCallableCodeAuthorizationSource, DaemonCodeGraphReadAdmission, + DaemonCallableCodeAuthorizationSource, DaemonCodeGraphReadAdmission, GRANT_HORIZON, + daemon_owned_project_source_access_at, project_open_source_access_authority, }; pub use invocation::semantic_evaluation::SemanticInvocationControlV1; #[cfg(any(test, feature = "test-helpers"))] diff --git a/crates/tracedecay-daemon-service/src/remote_protocol.rs b/crates/tracedecay-daemon-service/src/remote_protocol.rs index 1ddef26dfa..4ff0209caa 100644 --- a/crates/tracedecay-daemon-service/src/remote_protocol.rs +++ b/crates/tracedecay-daemon-service/src/remote_protocol.rs @@ -52,8 +52,6 @@ use tracedecay_store_runtime::{ mod observability; -pub use observability::remote_query_result_observation; - use tracedecay_store_runtime::{DaemonRemoteCredentialAuthorityV1, DaemonRemoteCredentialLookupV1}; struct DaemonRemoteEnrollmentProtocolPortV1 { @@ -459,3 +457,115 @@ mod recovery_control_tests { ); } } + +#[cfg(test)] +mod observation_tests { + use tracedecay_contracts::remote::composition::{ + AuthenticityClaimV1, AuthorizationClaimV1, IntegrityClaimV1, PendingLocalEvidenceV1, + PendingLocalObservationsV1, QueryManifestBindingV1, RemoteCompletenessV1, + RemoteFreshnessV1, RemoteQueryCompositionV1, ShardCoverageStateV1, + ShardQueryContributionV1, + }; + use tracedecay_contracts::remote::query::{ + RemoteExactObservationResultV1, RemoteQueryResultV1, + }; + use tracedecay_domain::{CoverageStateV1, ObservedTernaryV1}; + + use super::observability::remote_query_result_observation; + + fn remote_query_result( + coverage: ShardCoverageStateV1, + pending_local: PendingLocalEvidenceV1, + ) -> RemoteQueryResultV1 { + RemoteQueryResultV1 { + composition: RemoteQueryCompositionV1 { + contributions: vec![ShardQueryContributionV1 { + manifest: QueryManifestBindingV1 { + brain_id: "brain.remote-coverage".to_owned(), + shard_id: "shard.remote-coverage".to_owned(), + generation_id: "generation.remote-coverage".to_owned(), + schema_digest: [1; 32], + watermark_sequence: 1, + placement_revision: 1, + authority_epoch: 1, + cache_age_millis: 0, + cache_lag_commits: 0, + }, + integrity: IntegrityClaimV1::Verified, + authenticity: AuthenticityClaimV1::Authenticated, + freshness: RemoteFreshnessV1::Current, + completeness: RemoteCompletenessV1::Complete, + authorization: AuthorizationClaimV1::Authorized, + coverage, + authority_receipt: None, + value: None, + reason_code: (coverage != ShardCoverageStateV1::Complete) + .then(|| "remote_shard_degraded".to_owned()), + }], + pending_local, + coverage, + }, + observation: RemoteExactObservationResultV1::NotFound, + } + } + + #[test] + fn remote_query_coverage_preserves_real_shard_and_pending_counts() { + let result = remote_query_result( + ShardCoverageStateV1::Stale, + PendingLocalObservationsV1 { + count: 3, + oldest_age_millis: Some(9), + has_sequence_gap: false, + has_quarantined: false, + } + .into(), + ); + result.validate().expect("valid stale remote query result"); + + let observation = remote_query_result_observation( + "request.remote-coverage", + 1, + &result, + ObservedTernaryV1::Yes, + ); + + assert_eq!(observation.expected_shards, Some(1)); + assert_eq!(observation.observed_shards, Some(1)); + assert_eq!(observation.pending_local_evidence, Some(3)); + assert_eq!(observation.terminal_succeeded, ObservedTernaryV1::Yes); + assert_eq!(observation.coverage, CoverageStateV1::Stale); + assert_eq!( + observation.unavailable_reason.as_deref(), + Some("pending_local_evidence") + ); + } + + #[test] + fn remote_query_coverage_does_not_fabricate_unavailable_pending_count() { + let result = remote_query_result( + ShardCoverageStateV1::Unknown, + PendingLocalEvidenceV1::Unavailable { + reason: tracedecay_contracts::remote::composition::PendingLocalUnavailableReasonV1::AuthorityUnavailable, + }, + ); + result + .validate() + .expect("valid unavailable remote query result"); + + let observation = remote_query_result_observation( + "request.remote-coverage-unavailable", + 1, + &result, + ObservedTernaryV1::Unknown, + ); + + assert_eq!(observation.pending_local_evidence, None); + assert_eq!(observation.terminal_succeeded, ObservedTernaryV1::Unknown); + assert_eq!(observation.coverage, CoverageStateV1::Unknown); + assert_eq!( + observation.unavailable_reason.as_deref(), + Some("pending_local_authority_unavailable") + ); + } +} diff --git a/crates/tracedecay-daemon-service/src/remote_protocol/observability.rs b/crates/tracedecay-daemon-service/src/remote_protocol/observability.rs index 2fc4649919..6f18cbbcf2 100644 --- a/crates/tracedecay-daemon-service/src/remote_protocol/observability.rs +++ b/crates/tracedecay-daemon-service/src/remote_protocol/observability.rs @@ -115,7 +115,7 @@ pub(super) fn record_remote_query_response( ); } -pub fn remote_query_result_observation( +pub(super) fn remote_query_result_observation( operation_ref: &str, expected_shards: usize, result: &RemoteQueryResultV1, diff --git a/crates/tracedecay-graph-query/src/lib.rs b/crates/tracedecay-graph-query/src/lib.rs index 6a2524c78c..35565c61c0 100644 --- a/crates/tracedecay-graph-query/src/lib.rs +++ b/crates/tracedecay-graph-query/src/lib.rs @@ -45,9 +45,11 @@ pub use queries::{ pub use source_authority::{ CodeGraphSourceAuthorityPort, CodeGraphSourceBindFuture, CodeGraphSourceBindRequest, }; +#[cfg(any(test, feature = "test-helpers"))] +pub use verified_query::admitted_verified_graph_query_port; pub use verified_query::{ AdmittedVerifiedGraphQueryPort, VerifiedGraphQuery, VerifiedGraphQueryFuture, - VerifiedGraphQueryPort, VerifiedGraphQueryRequest, admitted_verified_graph_query_port, + VerifiedGraphQueryPort, VerifiedGraphQueryRequest, admitted_verified_graph_query_port_with_source, open_verified_graph_query, }; diff --git a/crates/tracedecay-graph-query/src/verified_query.rs b/crates/tracedecay-graph-query/src/verified_query.rs index 68ae8bc36f..157ea43e18 100644 --- a/crates/tracedecay-graph-query/src/verified_query.rs +++ b/crates/tracedecay-graph-query/src/verified_query.rs @@ -114,6 +114,7 @@ impl VerifiedGraphQueryPort for AdmittedVerifiedGraphQueryPort { } } +#[cfg(any(test, feature = "test-helpers"))] #[must_use] pub fn admitted_verified_graph_query_port( admission: Arc, diff --git a/crates/tracedecay/src/daemon/invocation_tests/types_tests.rs b/crates/tracedecay/src/daemon/invocation_tests/types_tests.rs index a8525ea52d..1052357d1c 100644 --- a/crates/tracedecay/src/daemon/invocation_tests/types_tests.rs +++ b/crates/tracedecay/src/daemon/invocation_tests/types_tests.rs @@ -995,7 +995,6 @@ async fn feedback_admission_conflicts_construct_zero_losing_producers() { project.path().to_path_buf(), scope.clone(), Arc::clone(graph.configuration_runtime()), - crate::daemon::project_open_owners::daemon_owned_project_source_access_at, )), ), ) @@ -1042,7 +1041,6 @@ async fn feedback_admission_conflicts_construct_zero_losing_producers() { project.path().to_path_buf(), scope.clone(), Arc::clone(graph.configuration_runtime()), - crate::daemon::project_open_owners::daemon_owned_project_source_access_at, )), ) .await; @@ -1130,7 +1128,6 @@ async fn feedback_admission_conflicts_construct_zero_losing_producers() { publisher_root, publisher_scope, publisher_configuration, - crate::daemon::project_open_owners::daemon_owned_project_source_access_at, )), ) .await diff --git a/crates/tracedecay/src/daemon/project_composition.rs b/crates/tracedecay/src/daemon/project_composition.rs index dbc2f21efb..eaa7b0703f 100644 --- a/crates/tracedecay/src/daemon/project_composition.rs +++ b/crates/tracedecay/src/daemon/project_composition.rs @@ -7,7 +7,9 @@ use super::*; use tracedecay_code_index_runtime::code_index_scheduler; use tracedecay_daemon_identity::profile_identity; -use tracedecay_daemon_service::DaemonSemanticRuntimeRegistrationError; +use tracedecay_daemon_service::{ + DaemonSemanticRuntimeRegistrationError, daemon_owned_project_source_access_at, +}; use tracedecay_runtime_core::logging::log_daemon_event; use tracedecay_semantic_contracts::SemanticResourceCeilings; use tracedecay_session_runtime::session_sync::DaemonSessionSyncConfig; @@ -1194,7 +1196,7 @@ impl ProjectOpenInputs<'_> { user_session_db.clone(), ]) .await; - let delivery_access = project_open_owners::daemon_owned_project_source_access_at( + let delivery_access = daemon_owned_project_source_access_at( &code_index.scope, self.canonical_project_path, runtime_configuration, @@ -1914,7 +1916,6 @@ fn project_code_index_authorities( canonical_project_path.to_path_buf(), scope.clone(), Arc::clone(cg.configuration_runtime()), - crate::daemon::project_open_owners::daemon_owned_project_source_access_at, ), ); let search_admission = tracedecay_daemon_service::admit_query_mcp_read( diff --git a/crates/tracedecay/src/daemon/project_open_owners.rs b/crates/tracedecay/src/daemon/project_open_owners.rs index d9104daf5b..4b80c442ff 100644 --- a/crates/tracedecay/src/daemon/project_open_owners.rs +++ b/crates/tracedecay/src/daemon/project_open_owners.rs @@ -11,12 +11,10 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use tracedecay_application::advisory::GitHubRepositoryTargetV1; -use tracedecay_application::project_open_authorization::{ - ProjectOpenSourceAccessAuthorityV1, project_open_work_grant, -}; +use tracedecay_application::project_open_authorization::project_open_work_grant; use tracedecay_contracts::{ApplicationContractError, ResolvedScope, now_micros}; use tracedecay_domain::feedback::GitHubPullRequestIdV1; -use tracedecay_domain::{ActorId, ProjectId, UtcMicros, canonical_sha256}; +use tracedecay_domain::{ProjectId, UtcMicros, canonical_sha256}; use super::DaemonInvocationState; use crate::mcp::McpServer; @@ -26,17 +24,16 @@ use tracedecay_application::semantic_runtime::{ InitialSemanticActivationRestoreV1, ProjectSemanticActivationExt, classify_initial_semantic_activation_restore, }; -use tracedecay_application::source_authorization::{ - ProjectSourceAccessSnapshot, ProjectSourceAccessSnapshotPort, -}; +use tracedecay_application::source_authorization::ProjectSourceAccessSnapshot; use tracedecay_code_index_runtime::git_transactions::DaemonGitIndexTransactionServiceRegistry; -use tracedecay_daemon_service::DaemonCallableCodeAuthorizationSource; use tracedecay_daemon_service::{ - DaemonContextScoutRuntimeRegistrationError, DaemonFeedbackRuntimeRegistrationError, - DaemonNativeIntegrationRuntimeRegistrar, DaemonWorkProposalRoutingAuthorityV1, + DaemonCallableCodeAuthorizationSource, DaemonContextScoutRuntimeRegistrationError, + DaemonFeedbackRuntimeRegistrationError, DaemonNativeIntegrationRuntimeRegistrar, + DaemonWorkProposalRoutingAuthorityV1, daemon_owned_project_source_access_at, + project_open_source_access_authority, project_owner_registration::{ ProjectSourceEditAuthorizationV1, ProjectSourceEditOwnerV1, SourceEditMutationGate, - production_lsp_registration, project_open_lsp_scope_grant, project_owner_capabilities, + production_lsp_registration, project_open_lsp_scope_grant, }, }; use tracedecay_domain::errors::{Result, TraceDecayError}; @@ -59,8 +56,6 @@ pub(crate) use automation_effect_recovery::reconcile_project_open_automation_eff use primitive_runtime::open_and_register_project_primitive_runtime; -const DAEMON_REQUESTER: &str = "actor.tracedecay-daemon.project-open"; -const GRANT_HORIZON: Duration = Duration::from_hours(24); const POLICY_REVISION_V1: u64 = 1; const LSP_DIAGNOSTICS_QUIET: Duration = Duration::from_secs(2); pub(super) use tracedecay_daemon_service::{ @@ -543,7 +538,6 @@ pub(super) async fn register_project_open_production_owners( project_root.to_path_buf(), scope.clone(), Arc::clone(graph.configuration_runtime()), - crate::daemon::project_open_owners::daemon_owned_project_source_access_at, )), ), label = "daemon.project.open.owners.feedback" @@ -1270,34 +1264,6 @@ fn github_repository_from_remote(remote: &str) -> Option<(String, String)> { .then_some((target.owner, target.repository)) } -pub(crate) fn daemon_owned_project_source_access_at( - scope: &ResolvedScope, - project_root: &Path, - configuration: &tracedecay_configuration::config::PinnedRuntimeConfiguration, - observed_at: UtcMicros, -) -> std::result::Result { - project_open_source_access_authority()?.source_access_at( - scope, - project_root, - configuration, - observed_at, - ) -} - -fn project_open_source_access_authority() --> std::result::Result { - let requester = ActorId::new(DAEMON_REQUESTER.to_owned()).map_err(|_| { - ApplicationContractError::Inconsistent { - field: "project-open requester", - } - })?; - Ok(ProjectOpenSourceAccessAuthorityV1::new( - requester, - project_owner_capabilities()?, - GRANT_HORIZON, - )) -} - pub(super) fn project_open_retained_grant( access: &ProjectSourceAccessSnapshot, observed_at: UtcMicros, diff --git a/crates/tracedecay/src/daemon/project_open_owners/advisory_runtime.rs b/crates/tracedecay/src/daemon/project_open_owners/advisory_runtime.rs index cd99df33d5..5b49c03fca 100644 --- a/crates/tracedecay/src/daemon/project_open_owners/advisory_runtime.rs +++ b/crates/tracedecay/src/daemon/project_open_owners/advisory_runtime.rs @@ -71,10 +71,7 @@ use tracedecay_lsp::{ }; use tracedecay_session_memory::context::MonotonicDeadline; -use super::{ - DaemonInvocationState, POLICY_REVISION_V1, daemon_owned_project_source_access_at, - register_semantic_configuration_owners, -}; +use super::{DaemonInvocationState, POLICY_REVISION_V1, register_semantic_configuration_owners}; use crate::daemon::context_scout_lifecycle::{ AuthorityRegistrationV1, register_context_scout_lifecycle_authority, unregister_context_scout_lifecycle_authority, @@ -96,7 +93,8 @@ use tracedecay_daemon_service::{ DaemonAdvisoryCycleInvocationOwner, DaemonAdvisoryCycleInvocationPort, DaemonAdvisoryCycleInvocationRequest, HookOrchestrationRequestV1, HookOrchestrationTriggerV1, HookOrchestrationWorkOutcomeV1, advisory_cycle_invocation_result, - daemon_operation_event_authority, register_hook_orchestration_runtime, + daemon_operation_event_authority, daemon_owned_project_source_access_at, + project_open_source_access_authority, register_hook_orchestration_runtime, unregister_hook_orchestration_runtime, }; use tracedecay_domain::errors::{Result, TraceDecayError}; @@ -1454,7 +1452,7 @@ async fn register_project_delivery_read_authority( } }; let source_access = - super::project_open_source_access_authority().map_err(|error| TraceDecayError::Config { + project_open_source_access_authority().map_err(|error| TraceDecayError::Config { message: format!("project-open delivery source access is invalid: {error}"), })?; invocation diff --git a/crates/tracedecay/src/daemon/project_open_owners/git_catalog_tests.rs b/crates/tracedecay/src/daemon/project_open_owners/git_catalog_tests.rs index acea8144d7..f72ce5b9e0 100644 --- a/crates/tracedecay/src/daemon/project_open_owners/git_catalog_tests.rs +++ b/crates/tracedecay/src/daemon/project_open_owners/git_catalog_tests.rs @@ -1,4 +1,3 @@ -use super::{GRANT_HORIZON, daemon_owned_project_source_access_at}; use crate::runtime_ports::compose_application_catalog_snapshot; use tracedecay_application::git_intelligence::NativeGitIntelligence; use tracedecay_code_index_runtime::git_transactions::DaemonGitIndexTransactionServiceRegistry; @@ -8,6 +7,7 @@ use tracedecay_contracts::{ DisclosureClass, GitIndexOperationBindingV1, GitIndexPreviewRequestV1, GitIndexTransactionPort, IdempotencyKey, OperationTermination, PolicyDecisionRef, RequestContext, RequestId, }; +use tracedecay_daemon_service::{GRANT_HORIZON, daemon_owned_project_source_access_at}; use tracedecay_domain::git::{ GitDiffScopeV1, GitIndexPreviewDispositionV1, GitIndexPreviewV1, GitIndexReceiptOutcomeV1, GitIndexTransactionOperationV1, GitIndexUnsupportedStateV1, diff --git a/crates/tracedecay/src/daemon/remote_protocol_tests.rs b/crates/tracedecay/src/daemon/remote_protocol_tests.rs index 2a08ade061..8c95e7cd96 100644 --- a/crates/tracedecay/src/daemon/remote_protocol_tests.rs +++ b/crates/tracedecay/src/daemon/remote_protocol_tests.rs @@ -3,16 +3,10 @@ use std::sync::Arc; use tracedecay_contracts::remote::auth::{ OpaqueRemoteCredential, RemoteEnrollmentAdmissionEvidenceV1, }; -use tracedecay_contracts::remote::composition::{ - AuthenticityClaimV1, AuthorizationClaimV1, IntegrityClaimV1, PendingLocalEvidenceV1, - PendingLocalObservationsV1, QueryManifestBindingV1, RemoteCompletenessV1, RemoteFreshnessV1, - RemoteQueryCompositionV1, ShardCoverageStateV1, ShardQueryContributionV1, -}; use tracedecay_contracts::remote::credential_admission::{ RemoteCredentialAdmissionErrorV1, RemoteCredentialAdmissionPortV1, RemoteCredentialAdmissionServiceV1, RemoteCredentialUseV1, }; -use tracedecay_contracts::remote::query::{RemoteExactObservationResultV1, RemoteQueryResultV1}; use tracedecay_contracts::remote::status::{ RemoteOperationalReadinessV1, RemoteOperationalStatusReadV1, }; @@ -21,10 +15,10 @@ use tracedecay_contracts::{ PolicyDecisionRef, RemoteListenerReadV1, RemoteOperationalReadV1, ResolvedScope, }; use tracedecay_domain::{ - ActorId, BrainNodeId, ComponentVersion, CoverageStateV1, CurrentRemoteAuthorityStateV1, - EnrollmentGrantV1, EntityId, ManifestDigest, ObservedTernaryV1, ProjectId, RefId, - RemoteCapabilityV1, RemoteCredentialFingerprintV1, RemoteRepositoryScopeV1, RepositoryId, - RepositoryStateSnapshotId, UtcMicros, WorktreeId, canonical_sha256, + ActorId, BrainNodeId, ComponentVersion, CurrentRemoteAuthorityStateV1, EnrollmentGrantV1, + EntityId, ManifestDigest, ProjectId, RefId, RemoteCapabilityV1, RemoteCredentialFingerprintV1, + RemoteRepositoryScopeV1, RepositoryId, RepositoryStateSnapshotId, UtcMicros, WorktreeId, + canonical_sha256, }; use tracedecay_rusqlite_runtime::remote::{ RemoteSpoolKeyV1, RemoteSpoolKeyringV1, RemoteSqliteStorageErrorV1, @@ -47,102 +41,6 @@ impl RemoteSpoolKeyringV1 for TestRemoteKeyring { } } -fn remote_query_result( - coverage: ShardCoverageStateV1, - pending_local: PendingLocalEvidenceV1, -) -> RemoteQueryResultV1 { - RemoteQueryResultV1 { - composition: RemoteQueryCompositionV1 { - contributions: vec![ShardQueryContributionV1 { - manifest: QueryManifestBindingV1 { - brain_id: "brain.remote-coverage".to_owned(), - shard_id: "shard.remote-coverage".to_owned(), - generation_id: "generation.remote-coverage".to_owned(), - schema_digest: [1; 32], - watermark_sequence: 1, - placement_revision: 1, - authority_epoch: 1, - cache_age_millis: 0, - cache_lag_commits: 0, - }, - integrity: IntegrityClaimV1::Verified, - authenticity: AuthenticityClaimV1::Authenticated, - freshness: RemoteFreshnessV1::Current, - completeness: RemoteCompletenessV1::Complete, - authorization: AuthorizationClaimV1::Authorized, - coverage, - authority_receipt: None, - value: None, - reason_code: (coverage != ShardCoverageStateV1::Complete) - .then(|| "remote_shard_degraded".to_owned()), - }], - pending_local, - coverage, - }, - observation: RemoteExactObservationResultV1::NotFound, - } -} - -#[test] -fn remote_query_coverage_preserves_real_shard_and_pending_counts() { - let result = remote_query_result( - ShardCoverageStateV1::Stale, - PendingLocalObservationsV1 { - count: 3, - oldest_age_millis: Some(9), - has_sequence_gap: false, - has_quarantined: false, - } - .into(), - ); - result.validate().expect("valid stale remote query result"); - - let observation = tracedecay_daemon_service::remote_protocol::remote_query_result_observation( - "request.remote-coverage", - 1, - &result, - ObservedTernaryV1::Yes, - ); - - assert_eq!(observation.expected_shards, Some(1)); - assert_eq!(observation.observed_shards, Some(1)); - assert_eq!(observation.pending_local_evidence, Some(3)); - assert_eq!(observation.terminal_succeeded, ObservedTernaryV1::Yes); - assert_eq!(observation.coverage, CoverageStateV1::Stale); - assert_eq!( - observation.unavailable_reason.as_deref(), - Some("pending_local_evidence") - ); -} - -#[test] -fn remote_query_coverage_does_not_fabricate_unavailable_pending_count() { - let result = remote_query_result( - ShardCoverageStateV1::Unknown, - PendingLocalEvidenceV1::Unavailable { - reason: tracedecay_contracts::remote::composition::PendingLocalUnavailableReasonV1::AuthorityUnavailable, - }, - ); - result - .validate() - .expect("valid unavailable remote query result"); - - let observation = tracedecay_daemon_service::remote_protocol::remote_query_result_observation( - "request.remote-coverage-unavailable", - 1, - &result, - ObservedTernaryV1::Unknown, - ); - - assert_eq!(observation.pending_local_evidence, None); - assert_eq!(observation.terminal_succeeded, ObservedTernaryV1::Unknown); - assert_eq!(observation.coverage, CoverageStateV1::Unknown); - assert_eq!( - observation.unavailable_reason.as_deref(), - Some("pending_local_authority_unavailable") - ); -} - pub(crate) fn grant( brain_id: tracedecay_domain::BrainId, node_id: BrainNodeId, diff --git a/crates/tracedecay/src/daemon/retained_test_support.rs b/crates/tracedecay/src/daemon/retained_test_support.rs index 68d30b8bd2..cf9f7f2c38 100644 --- a/crates/tracedecay/src/daemon/retained_test_support.rs +++ b/crates/tracedecay/src/daemon/retained_test_support.rs @@ -15,13 +15,13 @@ use std::sync::Arc; use tokio::sync::Mutex; use tracedecay_lsp::LspSessionRegistry; -use super::project_open_owners::{ - daemon_owned_project_source_access_at, project_open_retained_grant, -}; +use super::project_open_owners::project_open_retained_grant; use tracedecay_code_index_runtime::code_index_scheduler::CodeIndexSchedulerRegistryV1; use tracedecay_code_index_runtime::resolved_scope_for_project; use tracedecay_daemon_protocol::invocation_now_micros; -use tracedecay_daemon_service::{DaemonInvocationService, DaemonRetainedRuntimeRegistrar}; +use tracedecay_daemon_service::{ + DaemonInvocationService, DaemonRetainedRuntimeRegistrar, daemon_owned_project_source_access_at, +}; use tracedecay_domain::errors::{Result, TraceDecayError}; #[derive(Clone)] diff --git a/crates/tracedecay/src/daemon/scheduler/combined_effect.rs b/crates/tracedecay/src/daemon/scheduler/combined_effect.rs index 742e4d7acf..3e684a3bed 100644 --- a/crates/tracedecay/src/daemon/scheduler/combined_effect.rs +++ b/crates/tracedecay/src/daemon/scheduler/combined_effect.rs @@ -819,6 +819,7 @@ mod tests { run_session_reflector_with_backend_and_retrieval_for_retained_settlement, scheduler_automation_effect, }; + use tracedecay_daemon_service::daemon_owned_project_source_access_at; struct CombinedAdmissionFixture { _temp: TempDir, @@ -875,7 +876,7 @@ mod tests { .await .expect("combined admission configuration"); let configuration_revision_id = configuration.revision_id().clone(); - let access = crate::daemon::project_open_owners::daemon_owned_project_source_access_at( + let access = daemon_owned_project_source_access_at( &scope, &project_root, &configuration, diff --git a/crates/tracedecay/tests/common/dashboard_configuration_test_runtime.rs b/crates/tracedecay/tests/common/dashboard_configuration_test_runtime.rs index 3f2eb68eb8..387bf6febe 100644 --- a/crates/tracedecay/tests/common/dashboard_configuration_test_runtime.rs +++ b/crates/tracedecay/tests/common/dashboard_configuration_test_runtime.rs @@ -25,6 +25,7 @@ use tracedecay_daemon_protocol::invocation_now_micros; use tracedecay_daemon_protocol::{DaemonInvocationOutcome, DaemonInvocationRequest}; use tracedecay_daemon_service::{ DaemonConfigurationRuntimeRegistrar, DaemonInvocationService, DaemonRetainedRuntimeRegistrar, + daemon_owned_project_source_access_at, }; use tracedecay_dashboard_api::{ DashboardApplicationRouters, DashboardApplicationRuntime, DashboardConfigurationApplyError, @@ -399,15 +400,11 @@ pub(crate) async fn register_dashboard_test_retained_runtime( .map_err(|error| TraceDecayError::Config { message: format!("dashboard test retained configuration is unavailable: {error}"), })?; - let retained_access = super::project_open_owners::daemon_owned_project_source_access_at( - &scope, - &project_root, - &configuration, - observed_at, - ) - .map_err(|error| TraceDecayError::Config { - message: format!("dashboard test retained access is invalid: {error}"), - })?; + let retained_access = + daemon_owned_project_source_access_at(&scope, &project_root, &configuration, observed_at) + .map_err(|error| TraceDecayError::Config { + message: format!("dashboard test retained access is invalid: {error}"), + })?; let retained_grant = super::project_open_owners::project_open_retained_grant(&retained_access, observed_at) .map_err(|error| TraceDecayError::Config {