cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit 1bf1ff69d0398e2874f1dbd7d9d14dd34e837046
parent 2a97f71a245a6d3acf53a88cdeb1f61a67b4d4ac
Author: triesap <tyson@radroots.org>
Date:   Tue, 30 Jun 2026 07:01:54 +0000

runtime: harden sdk adoption source guards

- rename active local replica status output to derived projection language
- extend migrated trade command guards against protocol and DVM bypass calls
- scope direct relay exceptions without legacy allowlist terminology
- validated with cargo test --workspace

Diffstat:
Msrc/ops/exec/core.rs | 11+++++++----
Msrc/ops/exec/runtime.rs | 5++++-
Msrc/out/terminal/renderers/store.rs | 4++--
Msrc/runtime/sdk.rs | 65+++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/runtime/store.rs | 40++++++++++++++++++++--------------------
Msrc/runtime/sync.rs | 18+++++++++---------
Msrc/view/runtime.rs | 4++--
Mtests/target_cli.rs | 60+++++++++++++++++++++++++++++++++++++-----------------------
8 files changed, 120 insertions(+), 87 deletions(-)

diff --git a/src/ops/exec/core.rs b/src/ops/exec/core.rs @@ -166,7 +166,7 @@ impl OperationService<HealthCheckRunRequest> for CoreOperationService<'_> { "event_store": store.event_store, "outbox": store.outbox, "integrity": store.integrity, - "legacy_replica": store.legacy_replica, + "derived_projection": store.derived_projection, "reason": store.reason, }, "account": { @@ -1287,10 +1287,13 @@ mod tests { assert_eq!(envelope.result["canonical_store"], "sdk"); assert_eq!(envelope.result["sdk_storage"], "directory"); assert_eq!( - envelope.result["legacy_replica"]["source"], - "legacy local replica · derived/migration source" + envelope.result["derived_projection"]["source"], + "local derived projection cache" + ); + assert_eq!( + envelope.result["derived_projection"]["state"], + "unconfigured" ); - assert_eq!(envelope.result["legacy_replica"]["state"], "unconfigured"); assert_eq!( envelope.result["event_store"]["store"]["integrity_ok"], true diff --git a/src/ops/exec/runtime.rs b/src/ops/exec/runtime.rs @@ -285,7 +285,10 @@ mod tests { envelope.result["source"], "SDK canonical event store and outbox" ); - assert_eq!(envelope.result["replica_db"], "legacy_derived_not_checked"); + assert_eq!( + envelope.result["replica_db"], + "derived_projection_not_checked" + ); assert_eq!(envelope.result["queue"]["pending_count"], 0); assert_eq!(envelope.result["queue"]["total_count"], 0); assert_eq!(envelope.result["actions"][0], "radroots sync pull"); diff --git a/src/out/terminal/renderers/store.rs b/src/out/terminal/renderers/store.rs @@ -31,9 +31,9 @@ impl TerminalOperationRenderer for StoreRenderer { common::push_path_field(&mut document, "Storage", result, &["sdk_storage"]); common::push_path_field( &mut document, - "Legacy", + "Derived", result, - &["legacy_replica", "state"], + &["derived_projection", "state"], ); common::push_count_field( &mut document, diff --git a/src/runtime/sdk.rs b/src/runtime/sdk.rs @@ -703,7 +703,7 @@ mod tests { lifecycle: &'static str, } - struct LegacyDirectRelayConsumer { + struct DirectRelayConsumerException { path: &'static str, required_tokens: &'static [&'static str], owner: &'static str, @@ -780,7 +780,7 @@ mod tests { section: "dependencies", name: "radroots_nostr_connect", owner: "sdk-myc-nip46-transport", - reason: "CLI Myc signer target parsing and NIP-46 relay transport bridge for SDK signing", + reason: "CLI Myc signer target parsing and NIP-46 relay transport wiring for SDK signing", lifecycle: "retain while CLI owns signer backend wiring", }, DirectRrRsDependency { @@ -800,23 +800,23 @@ mod tests { DirectRrRsDependency { section: "dependencies", name: "radroots_replica_db", - owner: "legacy-replica-and-market-projection", - reason: "legacy derived replica status, export, market reads, sync pull, basket lookup, and trade draft preflight", - lifecycle: "transitional until those derived projection surfaces migrate", + owner: "derived-projection-and-market-reads", + reason: "derived projection status, export, market reads, sync pull, basket lookup, and trade draft preflight", + lifecycle: "retain until those derived projection surfaces move behind SDK APIs", }, DirectRrRsDependency { section: "dependencies", name: "radroots_replica_db_schema", - owner: "legacy-replica-and-market-projection", - reason: "typed query filters for legacy market, basket, and order lookup projections", - lifecycle: "transitional until those derived projection surfaces migrate", + owner: "derived-projection-and-market-reads", + reason: "typed query filters for market, basket, and order lookup projections", + lifecycle: "retain until those derived projection surfaces move behind SDK APIs", }, DirectRrRsDependency { section: "dependencies", name: "radroots_replica_sync", - owner: "legacy-sync-pull-and-derived-replica", - reason: "legacy relay ingest, sync pull, market refresh, and derived replica state reporting", - lifecycle: "transitional until relay ingest and projection repair move behind SDK APIs", + owner: "sync-pull-and-derived-projection", + reason: "relay ingest, sync pull, market refresh, and derived projection state reporting", + lifecycle: "retain until relay ingest and projection repair move behind SDK APIs", }, DirectRrRsDependency { section: "dependencies", @@ -856,8 +856,8 @@ mod tests { DirectRrRsDependency { section: "dependencies", name: "radroots_sql_core", - owner: "legacy-replica-and-local-events", - reason: "SQLite executor for legacy derived replica and shared local-events storage", + owner: "derived-projection-and-local-events", + reason: "SQLite executor for derived projection and shared local-events storage", lifecycle: "transitional until those storage surfaces move behind SDK or shared runtime APIs", }, DirectRrRsDependency { @@ -869,22 +869,22 @@ mod tests { }, ]; - const LEGACY_DIRECT_RELAY_CONSUMERS: &[LegacyDirectRelayConsumer] = &[ - LegacyDirectRelayConsumer { + const DIRECT_RELAY_CONSUMER_EXCEPTIONS: &[DirectRelayConsumerException] = &[ + DirectRelayConsumerException { path: "src/runtime/order.rs", required_tokens: &["pub fn event_list(", "fetch_events_from_relays"], owner: "non-migrated-trade-event-and-derived-projection-reads", reason: "event listing, draft checks, and derived projection maintenance still use direct relay reads outside migrated trade mutation paths", lifecycle: "retain only for non-migrated read/projection surfaces", }, - LegacyDirectRelayConsumer { + DirectRelayConsumerException { path: "src/runtime/sync.rs", required_tokens: &["fetch_events_from_relays", "pull_with_fetcher"], owner: "sync.pull-and-market-refresh", - reason: "non-migrated relay ingest into the legacy derived replica", + reason: "relay ingest into the derived projection cache", lifecycle: "retain until relay ingest and derived projection repair migrate to SDK APIs", }, - LegacyDirectRelayConsumer { + DirectRelayConsumerException { path: "src/runtime/validation_receipt.rs", required_tokens: &["fetch_events_from_relays", "DirectRelayFetchReceipt"], owner: "validation.receipt.relay-reads", @@ -999,7 +999,7 @@ mod tests { label: "store status", path: "src/runtime/store.rs", start: "pub fn status(config: &RuntimeConfig) -> Result<LocalStatusView, CliSdkAdapterError>", - end: "fn legacy_replica_status(", + end: "fn derived_projection_status(", required_tokens: &[ "session.sdk()", "storage_status(StorageStatusRequest::new())", @@ -1048,6 +1048,19 @@ mod tests { "SqliteExecutor::open(&config.local.replica_db_path)", "outbox_idempotency_digest", "canonical_target_relays", + "radroots_sdk::protocol::order", + "build_order_request_draft", + "build_order_decision_draft", + "build_order_revision_proposal_draft", + "build_order_revision_decision_draft", + "build_order_cancellation_draft", + "parse_order_root_tag", + "parse_order_prev_tag", + "build_transition_proof_request_tags", + "build_transition_proof_result_tags", + "build_job_feedback_tags", + "KIND_TRADE_TRANSITION_PROOF", + "KIND_JOB_FEEDBACK", ]; #[test] @@ -1209,20 +1222,20 @@ mod tests { } #[test] - fn legacy_direct_relay_consumers_are_explicitly_allowlisted() { - let actual = legacy_direct_relay_consumer_paths(); - let expected = LEGACY_DIRECT_RELAY_CONSUMERS + fn direct_relay_consumer_exceptions_are_explicit() { + let actual = direct_relay_consumer_exception_paths(); + let expected = DIRECT_RELAY_CONSUMER_EXCEPTIONS .iter() .map(|consumer| consumer.path.to_owned()) .collect::<BTreeSet<_>>(); assert_eq!(actual, expected); - for consumer in LEGACY_DIRECT_RELAY_CONSUMERS { + for consumer in DIRECT_RELAY_CONSUMER_EXCEPTIONS { let source = crate_source(consumer.path); for token in consumer.required_tokens { assert!( source.contains(token), - "{} does not contain legacy direct-relay token `{token}`", + "{} does not contain direct-relay exception token `{token}`", consumer.path ); } @@ -1233,7 +1246,7 @@ mod tests { } #[test] - fn migrated_cli_paths_are_guarded_against_direct_relay_and_legacy_canonical_use() { + fn migrated_cli_paths_are_guarded_against_workflow_bypasses() { for guard in MIGRATED_CLI_PATH_GUARDS { let source = crate_source(guard.path); assert_migrated_path( @@ -1281,7 +1294,7 @@ mod tests { format!("{}:{}", dependency.section, dependency.name) } - fn legacy_direct_relay_consumer_paths() -> BTreeSet<String> { + fn direct_relay_consumer_exception_paths() -> BTreeSet<String> { let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); let mut files = Vec::new(); collect_rs_files(manifest_dir.join("src/runtime").as_path(), &mut files); diff --git a/src/runtime/store.rs b/src/runtime/store.rs @@ -20,12 +20,12 @@ use crate::runtime::config::RuntimeConfig; use crate::runtime::sdk::{CliSdkAdapterError, CliSdkSession, sdk_runtime, sdk_storage_root}; use crate::runtime::sync::ensure_sync_run_table; use crate::view::runtime::{ - LocalBackupView, LocalExportView, LocalInitView, LocalLegacyReplicaStatusView, + LocalBackupView, LocalDerivedProjectionStatusView, LocalExportView, LocalInitView, LocalReplicaCountsView, LocalReplicaSyncView, LocalRestoreView, LocalStatusView, SdkEventStoreStatusView, SdkIntegrityView, SdkOutboxStatusView, SdkSqliteStatusView, }; -const LEGACY_REPLICA_SOURCE: &str = "legacy local replica · derived/migration source"; +const DERIVED_PROJECTION_SOURCE: &str = "local derived projection cache"; const SDK_CANONICAL_SOURCE: &str = "SDK canonical event store and outbox"; const SDK_CANONICAL_STORE: &str = "sdk"; const SDK_BACKUP_KIND: &str = "sdk_canonical"; @@ -47,7 +47,7 @@ pub fn init(config: &RuntimeConfig) -> Result<LocalInitView, RuntimeError> { } else { "initialized".to_owned() }, - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), local_root: config.local.root.display().to_string(), replica_db: "ready".to_owned(), path: config.local.replica_db_path.display().to_string(), @@ -64,7 +64,7 @@ pub fn init_preflight(config: &RuntimeConfig) -> Result<LocalInitView, RuntimeEr let manifest = export_manifest(&executor)?; return Ok(LocalInitView { state: "ready".to_owned(), - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), local_root: config.local.root.display().to_string(), replica_db: "ready".to_owned(), path: config.local.replica_db_path.display().to_string(), @@ -75,7 +75,7 @@ pub fn init_preflight(config: &RuntimeConfig) -> Result<LocalInitView, RuntimeEr Ok(LocalInitView { state: "dry_run".to_owned(), - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), local_root: config.local.root.display().to_string(), replica_db: "missing".to_owned(), path: config.local.replica_db_path.display().to_string(), @@ -87,7 +87,7 @@ pub fn init_preflight(config: &RuntimeConfig) -> Result<LocalInitView, RuntimeEr pub fn status(config: &RuntimeConfig) -> Result<LocalStatusView, CliSdkAdapterError> { let sdk_root = sdk_storage_root(config); let sdk_existed_before_open = sdk_storage_files_exist(sdk_root.as_path()); - let legacy_replica = legacy_replica_status(config)?; + let derived_projection = derived_projection_status(config)?; let session = CliSdkSession::connect(config)?; let receipt = session.block_on(session.sdk().storage_status(StorageStatusRequest::new()))?; let integrity = session.block_on(session.sdk().integrity(IntegrityRequest::new()))?; @@ -97,17 +97,17 @@ pub fn status(config: &RuntimeConfig) -> Result<LocalStatusView, CliSdkAdapterEr sdk_existed_before_open, receipt, integrity, - legacy_replica, + derived_projection, )) } -fn legacy_replica_status( +fn derived_projection_status( config: &RuntimeConfig, -) -> Result<LocalLegacyReplicaStatusView, RuntimeError> { +) -> Result<LocalDerivedProjectionStatusView, RuntimeError> { if !config.local.replica_db_path.exists() { - return Ok(LocalLegacyReplicaStatusView { + return Ok(LocalDerivedProjectionStatusView { state: "unconfigured".to_owned(), - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), replica_db: "missing".to_owned(), path: config.local.replica_db_path.display().to_string(), replica_db_version: String::new(), @@ -134,9 +134,9 @@ fn legacy_replica_status( let manifest = export_manifest(&executor)?; let sync = radroots_replica_sync_status(&executor)?; - Ok(LocalLegacyReplicaStatusView { + Ok(LocalDerivedProjectionStatusView { state: "ready".to_owned(), - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), replica_db: "ready".to_owned(), path: config.local.replica_db_path.display().to_string(), replica_db_version: manifest.replica_db_version.clone(), @@ -218,7 +218,7 @@ pub fn export( if !config.local.replica_db_path.exists() { return Ok(LocalExportView { state: "unconfigured".to_owned(), - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), format: format.as_str().to_owned(), file: output.display().to_string(), records: 0, @@ -239,7 +239,7 @@ pub fn export( LocalExportFormatArg::Json => { let export = json!({ "kind": "local_export_manifest_v1", - "source": LEGACY_REPLICA_SOURCE, + "source": DERIVED_PROJECTION_SOURCE, "replica_db_version": manifest.replica_db_version, "backup_format_version": manifest.backup_format_version, "export_version": manifest.export_version, @@ -258,7 +258,7 @@ pub fn export( lines.push( json!({ "kind": "local_export_manifest", - "source": LEGACY_REPLICA_SOURCE, + "source": DERIVED_PROJECTION_SOURCE, "replica_db_version": manifest.replica_db_version, "backup_format_version": manifest.backup_format_version, "export_version": manifest.export_version, @@ -291,7 +291,7 @@ pub fn export( Ok(LocalExportView { state: "exported".to_owned(), - source: LEGACY_REPLICA_SOURCE.to_owned(), + source: DERIVED_PROJECTION_SOURCE.to_owned(), format: format.as_str().to_owned(), file: output.display().to_string(), records, @@ -347,7 +347,7 @@ fn sdk_status_view( sdk_existed_before_open: bool, receipt: StorageStatusReceipt, integrity: IntegrityReceipt, - legacy_replica: LocalLegacyReplicaStatusView, + derived_projection: LocalDerivedProjectionStatusView, ) -> LocalStatusView { let event_store_path = receipt .paths @@ -371,7 +371,7 @@ fn sdk_status_view( event_store: sdk_event_store_status_view(receipt.event_store, event_store_path), outbox: sdk_outbox_status_view(receipt.outbox, outbox_path), integrity: sdk_integrity_view(integrity), - legacy_replica, + derived_projection, reason, actions, } @@ -477,7 +477,7 @@ fn ensure_safe_sdk_backup_destination( ]; if forbidden_paths.iter().any(|forbidden| output == *forbidden) { return Err(RuntimeError::Config(format!( - "backup destination {} would overwrite canonical or legacy store data", + "backup destination {} would overwrite canonical or derived projection store data", output.display() ))); } diff --git a/src/runtime/sync.rs b/src/runtime/sync.rs @@ -307,7 +307,7 @@ where relay_count: config.relay.urls.len(), publish_policy: config.relay.publish_policy.as_str().to_owned(), freshness, - queue: legacy_sync_queue(queue.expected_count, queue.pending_count), + queue: derived_projection_sync_queue(queue.expected_count, queue.pending_count), target_relays: receipt.target_relays, connected_relays: receipt.connected_relays, acknowledged_relays: Vec::new(), @@ -414,7 +414,7 @@ fn sdk_sync_status_view(config: &RuntimeConfig, receipt: SyncStatusReceipt) -> S state: "ready".to_owned(), source: SDK_SYNC_SOURCE.to_owned(), local_root: config.local.root.display().to_string(), - replica_db: "legacy_derived_not_checked".to_owned(), + replica_db: "derived_projection_not_checked".to_owned(), relay_count, publish_policy: config.relay.publish_policy.as_str().to_owned(), freshness: sdk_sync_freshness(&receipt), @@ -513,7 +513,7 @@ fn sdk_push_action_view( state: state.to_owned(), source: SDK_PUSH_SOURCE.to_owned(), local_root: config.local.root.display().to_string(), - replica_db: "legacy_derived_not_checked".to_owned(), + replica_db: "derived_projection_not_checked".to_owned(), relay_count: config.relay.urls.len(), publish_policy: config.relay.publish_policy.as_str().to_owned(), freshness, @@ -608,7 +608,7 @@ fn sdk_sync_queue(receipt: &SyncStatusReceipt) -> SyncQueueView { } } -fn legacy_sync_queue(expected_count: usize, pending_count: usize) -> SyncQueueView { +fn derived_projection_sync_queue(expected_count: usize, pending_count: usize) -> SyncQueueView { SyncQueueView { expected_count, pending_count, @@ -730,7 +730,7 @@ fn inspect_sync(config: &RuntimeConfig) -> Result<SyncSnapshot, RuntimeError> { relay_count: config.relay.urls.len(), publish_policy: config.relay.publish_policy.as_str().to_owned(), freshness: missing_freshness(), - queue: legacy_sync_queue(0, 0), + queue: derived_projection_sync_queue(0, 0), reason: Some("local replica database is not initialized".to_owned()), actions: vec!["radroots store init".to_owned()], }); @@ -755,7 +755,7 @@ fn inspect_sync(config: &RuntimeConfig) -> Result<SyncSnapshot, RuntimeError> { relay_count, publish_policy, freshness, - queue: legacy_sync_queue(queue.expected_count, queue.pending_count), + queue: derived_projection_sync_queue(queue.expected_count, queue.pending_count), reason: Some("no relays are configured for this operator session".to_owned()), actions, }); @@ -774,7 +774,7 @@ fn inspect_sync(config: &RuntimeConfig) -> Result<SyncSnapshot, RuntimeError> { relay_count, publish_policy, freshness, - queue: legacy_sync_queue(queue.expected_count, queue.pending_count), + queue: derived_projection_sync_queue(queue.expected_count, queue.pending_count), reason: None, actions, }) @@ -1514,7 +1514,7 @@ mod tests { assert_eq!(view.state, "ready"); assert_eq!(view.source, "SDK canonical event store and outbox"); - assert_eq!(view.replica_db, "legacy_derived_not_checked"); + assert_eq!(view.replica_db, "derived_projection_not_checked"); assert_eq!(view.relay_count, 2); assert_eq!(view.queue.total_count, Some(0)); assert_eq!(view.queue.pending_count, 0); @@ -1586,7 +1586,7 @@ mod tests { assert_eq!(view.state, "dry_run"); assert_eq!(view.source, "SDK outbox push"); - assert_eq!(view.replica_db, "legacy_derived_not_checked"); + assert_eq!(view.replica_db, "derived_projection_not_checked"); assert_eq!(view.target_relays, vec!["wss://relay.example.com"]); assert_eq!(view.publishable_count, Some(1)); assert_eq!(view.published_count, Some(0)); diff --git a/src/view/runtime.rs b/src/view/runtime.rs @@ -611,7 +611,7 @@ pub struct LocalStatusView { pub event_store: SdkEventStoreStatusView, pub outbox: SdkOutboxStatusView, pub integrity: SdkIntegrityView, - pub legacy_replica: LocalLegacyReplicaStatusView, + pub derived_projection: LocalDerivedProjectionStatusView, #[serde(skip_serializing_if = "Option::is_none")] pub reason: Option<String>, #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -680,7 +680,7 @@ pub struct SdkIntegrityView { } #[derive(Debug, Clone, Serialize)] -pub struct LocalLegacyReplicaStatusView { +pub struct LocalDerivedProjectionStatusView { pub state: String, pub source: String, pub replica_db: String, diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -51,7 +51,7 @@ use support::{ const LISTING_ADDR: &str = "30402:1111111111111111111111111111111111111111111111111111111111111111:AAAAAAAAAAAAAAAAAAAAAg"; -const LEGACY_SYNC_PUSH_FARM_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA"; +const DERIVED_PROJECTION_SYNC_PUSH_FARM_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA"; fn test_order_id(value: &str) -> RadrootsOrderId { value.parse().expect("valid order id") @@ -618,7 +618,7 @@ fn read_relay_req_subscription_id(websocket: &mut tungstenite::WebSocket<TcpStre } } -fn seed_legacy_replica_sync_farm(sandbox: &RadrootsCliSandbox, d_tag: &str, pubkey: &str) { +fn seed_derived_projection_sync_farm(sandbox: &RadrootsCliSandbox, d_tag: &str, pubkey: &str) { let executor = SqliteExecutor::open(sandbox.replica_db_path()).expect("open replica"); migrations::run_all_up(&executor).expect("replica migrations"); farm::create( @@ -637,7 +637,7 @@ fn seed_legacy_replica_sync_farm(sandbox: &RadrootsCliSandbox, d_tag: &str, pubk location_country: None, }, ) - .expect("seed legacy replica sync farm"); + .expect("seed derived projection sync farm"); } fn seed_app_farm_record( @@ -3949,30 +3949,34 @@ fn store_backup_and_restore_use_sdk_canonical_store() { true ); assert_eq!(status["result"]["outbox"]["store"]["integrity_ok"], true); - assert_eq!(status["result"]["legacy_replica"]["state"], "unconfigured"); assert_eq!( - status["result"]["legacy_replica"]["source"], - "legacy local replica · derived/migration source" + status["result"]["derived_projection"]["state"], + "unconfigured" + ); + assert_eq!( + status["result"]["derived_projection"]["source"], + "local derived projection cache" ); assert!(sdk_root.join("event_store.sqlite").exists()); assert!(sdk_root.join("outbox.sqlite").exists()); - let legacy = sandbox.json_success(&["--format", "json", "store", "init"]); - assert_eq!(legacy["operation_id"], "store.init"); + let derived_projection_init = sandbox.json_success(&["--format", "json", "store", "init"]); + assert_eq!(derived_projection_init["operation_id"], "store.init"); - let status_after_legacy = sandbox.json_success(&["--format", "json", "store", "status", "get"]); + let status_after_projection = + sandbox.json_success(&["--format", "json", "store", "status", "get"]); assert_eq!( - status_after_legacy["result"]["source"], + status_after_projection["result"]["source"], "SDK canonical event store and outbox" ); assert_eq!( - status_after_legacy["result"]["legacy_replica"]["state"], + status_after_projection["result"]["derived_projection"]["state"], "ready" ); assert_eq!( - status_after_legacy["result"]["legacy_replica"]["source"], - "legacy local replica · derived/migration source" + status_after_projection["result"]["derived_projection"]["source"], + "local derived projection cache" ); let dry_run = @@ -6019,7 +6023,10 @@ fn sync_push_sdk_outbox_failure_reports_network_unavailable() { status["result"]["source"], "SDK canonical event store and outbox" ); - assert_eq!(status["result"]["replica_db"], "legacy_derived_not_checked"); + assert_eq!( + status["result"]["replica_db"], + "derived_projection_not_checked" + ); assert_eq!(status["result"]["queue"]["pending_count"], 1); assert_eq!(status["result"]["queue"]["ready_signed_count"], 1); @@ -6042,7 +6049,7 @@ fn sync_push_sdk_outbox_failure_reports_network_unavailable() { assert_eq!(value["errors"][0]["detail"]["source"], "SDK outbox push"); assert_eq!( value["errors"][0]["detail"]["replica_db"], - "legacy_derived_not_checked" + "derived_projection_not_checked" ); assert_eq!(value["errors"][0]["detail"]["target_relays"][0], relay); assert_eq!( @@ -6065,7 +6072,7 @@ fn sync_push_sdk_outbox_failure_reports_network_unavailable() { } #[test] -fn sync_push_ignores_legacy_replica_pending_queue_for_sdk_canonical_push() { +fn sync_push_ignores_derived_projection_pending_queue_for_sdk_canonical_push() { let sandbox = RadrootsCliSandbox::new(); sandbox.json_success(&["--format", "json", "account", "create"]); sandbox.json_success(&["--format", "json", "store", "init"]); @@ -6073,11 +6080,15 @@ fn sync_push_ignores_legacy_replica_pending_queue_for_sdk_canonical_push() { let selected_pubkey = signer["result"]["local"]["public_identity"]["public_key_hex"] .as_str() .expect("selected public key"); - seed_legacy_replica_sync_farm(&sandbox, LEGACY_SYNC_PUSH_FARM_D_TAG, selected_pubkey); + seed_derived_projection_sync_farm( + &sandbox, + DERIVED_PROJECTION_SYNC_PUSH_FARM_D_TAG, + selected_pubkey, + ); let executor = SqliteExecutor::open(sandbox.replica_db_path()).expect("open replica"); - let legacy_batch = - radroots_replica_pending_publish_batch(&executor).expect("legacy pending batch"); - assert!(legacy_batch.pending_count > 0); + let derived_projection_batch = radroots_replica_pending_publish_batch(&executor) + .expect("derived projection pending batch"); + assert!(derived_projection_batch.pending_count > 0); let value = sandbox.json_success(&[ "--format", @@ -6093,7 +6104,10 @@ fn sync_push_ignores_legacy_replica_pending_queue_for_sdk_canonical_push() { assert_eq!(value["operation_id"], "sync.push"); assert_eq!(value["result"]["state"], "ready"); assert_eq!(value["result"]["source"], "SDK outbox push"); - assert_eq!(value["result"]["replica_db"], "legacy_derived_not_checked"); + assert_eq!( + value["result"]["replica_db"], + "derived_projection_not_checked" + ); assert_eq!(value["result"]["queue"]["pending_count"], 0); assert_eq!(value["result"]["queue"]["total_count"], 0); assert_eq!(value["result"]["publishable_count"], 0); @@ -6134,7 +6148,7 @@ fn buyer_market_sync_basket_dry_runs_preflight_without_mutating_local_state() { assert_eq!(sync_push["result"]["source"], "SDK outbox push"); assert_eq!( sync_push["result"]["replica_db"], - "legacy_derived_not_checked" + "derived_projection_not_checked" ); assert_eq!(sync_push["result"]["queue"]["pending_count"], 0); assert_eq!(sync_push["result"]["queue"]["total_count"], 0); @@ -6176,7 +6190,7 @@ fn buyer_market_sync_basket_dry_runs_preflight_without_mutating_local_state() { assert_eq!(sync_push_ready["result"]["source"], "SDK outbox push"); assert_eq!( sync_push_ready["result"]["replica_db"], - "legacy_derived_not_checked" + "derived_projection_not_checked" ); assert_eq!( sync_push_ready["result"]["target_relays"][0],