rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

commit f03279a8e7f7bd27f234bc0e0a97efeeb9e4bfe5
parent c4bc8f4ab35ae2c066c6e439f68ee42ad1493193
Author: triesap <tyson@radroots.org>
Date:   Mon, 24 Aug 2026 08:15:30 +0000

test(rhi): close reconciliation integration wave

- Prove concurrent exact commits converge to one durable manifest.
- Bind cancellation, timeout, and bounded infinite-input recovery.
- Exercise lost-success replay across explicit close and reopen.
- Record wave qualification without adding runtime authority.

Diffstat:
MREADME | 10++++++++++
Mtests/package_boundary.rs | 3+++
Mtests/services_hardening_reconciliation_jobs.rs | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 190 insertions(+), 3 deletions(-)

diff --git a/README b/README @@ -239,6 +239,16 @@ coverage/outcome, attestation, and publication retain their later checkpoint owners. The exact machine contract is [`reconciliation_manifest.v1.json`](contracts/services_hardening/reconciliation_manifest.v1.json). +The Step 192 integration-wave qualification proves that concurrent exact +commits converge to one durable attempt and byte-identical manifest, a blocked +commit can be cancelled with no authoritative effect and retried, an exact +lost-success retry converges after close/reopen, and an infinite replay +inventory terminates at configured source count plus one before mutation. The +same corpus covers exact source deadlines, incomplete checkpoint exclusion, +lease expiry/reclaim, queue and result bounds, stale leases/generations, and +durable reopen behavior without adding runtime, scheduler, source, or network +authority. + ## Existing-state runtime foundation `open_rhi_runtime_foundation` opens only an already initialized database from diff --git a/tests/package_boundary.rs b/tests/package_boundary.rs @@ -729,6 +729,9 @@ fn readme_freezes_the_root_only_boundary_and_exact_baseline() { "[`reconciliation_commit.v1.json`](contracts/services_hardening/reconciliation_commit.v1.json)", "## Immutable reconciliation manifest", "[`reconciliation_manifest.v1.json`](contracts/services_hardening/reconciliation_manifest.v1.json)", + "The Step 192 integration-wave qualification proves that concurrent exact", + "lost-success retry converges after close/reopen", + "inventory terminates at configured source count plus one before mutation", "configured queue capacity is enforced beneath a fixed 65,536-job", "from an unexpired claimed job lease", "can be omitted, duplicated, reordered, or appended beyond", diff --git a/tests/services_hardening_reconciliation_jobs.rs b/tests/services_hardening_reconciliation_jobs.rs @@ -1,7 +1,7 @@ #![forbid(unsafe_code)] #![cfg(any(target_os = "linux", target_os = "macos"))] -use std::{error::Error, fs, os::unix::fs::PermissionsExt, path::Path}; +use std::{error::Error, fs, os::unix::fs::PermissionsExt, path::Path, time::Duration}; use radroots_service_sqlite::{MigrationAppliedAtUnixSeconds, MigrationBuildIdentity}; use radroots_storage::event::SourceGeneration; @@ -1052,7 +1052,12 @@ async fn source_replay_commit_is_atomic_idempotent_and_mints_durable_cursor_evid ] ); let canonical_manifest = manifest.canonical_bytes().to_vec(); + host.close() + .await + .expect("close before lost-success replay"); + let host = open_writer(&runtime, &metadata).await; + let attempts = host.repositories().reconciliation_attempts(); let reconciled = attempts .commit_source_replays(lease, plan.clone(), [retry_replay]) .await @@ -1116,6 +1121,165 @@ async fn source_replay_commit_is_atomic_idempotent_and_mints_durable_cursor_evid } #[tokio::test] +async fn concurrent_exact_commits_converge_to_one_attempt_and_one_manifest() { + let started_ms = 1_784_347_400_000; + let (root, runtime, metadata, configuration, host, lease, plan) = + replay_fixture("replay-concurrent-commit", EXAMPLE, started_ms).await; + let request = &plan.requests()[0]; + let wire = replay_wire(); + let make_replay = || { + RhiReconciliationSourceReplayPlan::from_request(&plan, request, &configuration, None) + .expect("replay plan") + .finish( + request, + RhiTradeSourceCompletion::Complete, + now(started_ms), + now(started_ms + 2_000), + [admitted_replay(&configuration, &wire, 1_784_347_400)], + ) + .expect("replay") + }; + let left_replay = make_replay(); + let right_replay = make_replay(); + let attempts = host.repositories().reconciliation_attempts(); + let (left, right) = tokio::join!( + attempts.commit_source_replays(lease, plan.clone(), [left_replay]), + attempts.commit_source_replays(lease, plan.clone(), [right_replay]), + ); + let left = left.expect("left exact commit"); + let right = right.expect("right exact commit"); + assert_eq!(u8::from(left.created()) + u8::from(right.created()), 1); + assert_eq!( + u8::from(left.dirty_generation_advanced()) + u8::from(right.dirty_generation_advanced()), + 1 + ); + let left = left + .into_evidence_manifest( + UnixTimeSeconds::new(1_784_347_403), + RhiReconciliationScopePrerequisites::Satisfied, + ) + .expect("left manifest"); + let right = right + .into_evidence_manifest( + UnixTimeSeconds::new(1_784_347_403), + RhiReconciliationScopePrerequisites::Satisfied, + ) + .expect("right manifest"); + assert_eq!(left.digest(), right.digest()); + assert_eq!(left.canonical_bytes(), right.canonical_bytes()); + host.close().await.expect("close"); + + let mut connection = fixture_connection(&runtime).await; + let counts: (i64, i64, i64) = sqlx::query_as( + r#"SELECT + (SELECT COUNT(*) FROM evidence_reconciliations), + (SELECT COUNT(*) FROM evidence_reconciliation_sources), + (SELECT generation FROM trade_dirty_generations)"#, + ) + .fetch_one(&mut connection) + .await + .expect("durable converged counts"); + assert_eq!(counts, (1, 1, 2)); + connection.close().await.expect("fixture close"); + drop((configuration, metadata, runtime, root)); +} + +#[tokio::test] +async fn cancelled_blocked_commit_has_no_effect_and_exact_retry_succeeds() { + let started_ms = 1_784_347_500_000; + let (root, runtime, metadata, configuration, host, lease, plan) = + replay_fixture("replay-cancelled-commit", EXAMPLE, started_ms).await; + let request = &plan.requests()[0]; + let wire = replay_wire(); + let make_replay = || { + RhiReconciliationSourceReplayPlan::from_request(&plan, request, &configuration, None) + .expect("replay plan") + .finish( + request, + RhiTradeSourceCompletion::Complete, + now(started_ms), + now(started_ms + 2_000), + [admitted_replay(&configuration, &wire, 1_784_347_500)], + ) + .expect("replay") + }; + let cancelled_replay = make_replay(); + let retry_replay = make_replay(); + let mut blocker = fixture_connection(&runtime).await; + sqlx::query("BEGIN IMMEDIATE") + .execute(&mut blocker) + .await + .expect("exclusive SQLite write blocker"); + + let attempts = host.repositories().reconciliation_attempts(); + let cancelled = tokio::time::timeout( + Duration::from_millis(100), + attempts.commit_source_replays(lease, plan.clone(), [cancelled_replay]), + ) + .await; + assert!(cancelled.is_err(), "blocked commit must remain cancellable"); + let attempt_count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM evidence_reconciliations") + .fetch_one(&mut blocker) + .await + .expect("no attempt before blocker release"); + assert_eq!(attempt_count, 0); + sqlx::query("ROLLBACK") + .execute(&mut blocker) + .await + .expect("release blocker"); + blocker.close().await.expect("blocker close"); + tokio::task::yield_now().await; + + let committed = attempts + .commit_source_replays(lease, plan, [retry_replay]) + .await + .expect("retry after cancellation"); + assert!(committed.created()); + assert_eq!(committed.source_result_count(), 1); + host.close().await.expect("close"); + drop((configuration, metadata, runtime, root)); +} + +#[tokio::test] +async fn commit_inventory_bounds_infinite_iterators_before_any_mutation() { + let started_ms = 1_784_347_600_000; + let (root, runtime, metadata, configuration, host, lease, plan) = + replay_fixture("replay-bounded-commit", EXAMPLE, started_ms).await; + let request = &plan.requests()[0]; + let wire = replay_wire(); + let make_replay = || { + RhiReconciliationSourceReplayPlan::from_request(&plan, request, &configuration, None) + .expect("replay plan") + .finish( + request, + RhiTradeSourceCompletion::Complete, + now(started_ms), + now(started_ms + 2_000), + [admitted_replay(&configuration, &wire, 1_784_347_600)], + ) + .expect("replay") + }; + let exact_replay = make_replay(); + let error = host + .repositories() + .reconciliation_attempts() + .commit_source_replays(lease, plan.clone(), std::iter::repeat_with(make_replay)) + .await + .expect_err("infinite inventory exceeds the exact source count"); + assert_eq!(error.kind(), RhiReconciliationCommitErrorKind::InvalidInput); + + let committed = host + .repositories() + .reconciliation_attempts() + .commit_source_replays(lease, plan, [exact_replay]) + .await + .expect("exact bounded retry"); + assert!(committed.created()); + host.close().await.expect("close"); + drop((configuration, metadata, runtime, root)); +} + +#[tokio::test] async fn incomplete_results_never_advance_and_stale_leases_fail_closed() { let started_ms = 1_784_347_200_000; let (root, runtime, metadata, configuration, host, lease, plan) = @@ -1127,9 +1291,9 @@ async fn incomplete_results_never_advance_and_stale_leases_fail_closed() { .expect("replay plan") .finish( request, - RhiTradeSourceCompletion::IncompleteUnavailable, + RhiTradeSourceCompletion::IncompleteTimeout, now(started_ms), - now(started_ms + 2_000), + now(started_ms + 10_000), [admitted_replay(&configuration, &wire, 1_784_347_200)], ) .expect("incomplete replay"); @@ -1198,6 +1362,16 @@ async fn incomplete_results_never_advance_and_stale_leases_fail_closed() { drop((configuration, metadata, runtime, root)); } +async fn fixture_connection(runtime: &RhiRuntimeContext) -> SqliteConnection { + let options = SqliteConnectOptions::new() + .filename(runtime.artifacts().state_database()) + .create_if_missing(false) + .foreign_keys(true); + SqliteConnection::connect_with(&options) + .await + .expect("offline fixture connection") +} + async fn attempt_fixture( instance: &str, ) -> (