app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

focused_availability_outcomes.rs (39836B)


      1 use std::error::Error;
      2 
      3 use harvestcircle_application::availability_outcomes::{FetchTargetState, TargetFingerprint};
      4 use harvestcircle_application::{
      5     AvailabilityDiscoveryOutcome, AvailabilityDiscoveryProgress, AvailabilityDiscoveryRequest,
      6     AvailabilityDiscoveryState, AvailabilityDiscoveryStopReason,
      7     AvailabilityDiscoveryTargetOutcome, AvailabilityDiscoveryUsage, AvailabilityLocalQueryScope,
      8     DISCOVERY_FETCH_RAW_RESERVATION_BYTES, MAX_DISCOVERY_FETCH_CALLS, MAX_DISCOVERY_METADATA_BYTES,
      9     MAX_DISCOVERY_RETURNED_EVENTS, MAX_DISCOVERY_RETURNED_PER_TARGET, MAX_DISCOVERY_TARGETS,
     10     RequestId, SessionGeneration,
     11 };
     12 use harvestcircle_domain::error::AvailabilityFailure;
     13 use harvestcircle_domain::{
     14     AvailabilityQueryContext, AvailabilityQueryError, PublicKey, SafeError, SafeErrorCode,
     15 };
     16 use radroots_transport::outcome::FetchTargetOutcome;
     17 
     18 const AUTHOR_HEX: &str = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
     19 
     20 fn scope() -> AvailabilityLocalQueryScope {
     21     AvailabilityLocalQueryScope::new(
     22         PublicKey::from_hex(AUTHOR_HEX).expect("fixed public curve author"),
     23         AvailabilityQueryContext::new([1; 32], [2; 32], u64::MAX, u64::MAX)
     24             .expect("nonzero structural context and store"),
     25         SessionGeneration::from_value(u64::MAX),
     26     )
     27 }
     28 
     29 fn fingerprint(index: u8) -> TargetFingerprint {
     30     TargetFingerprint::parse(format!("{index:064x}")).expect("fixed public target fingerprint")
     31 }
     32 
     33 fn request(targets: Vec<TargetFingerprint>) -> AvailabilityDiscoveryRequest {
     34     AvailabilityDiscoveryRequest::new(
     35         RequestId::new(7).expect("nonzero request"),
     36         scope(),
     37         targets,
     38         30_000,
     39     )
     40     .expect("bounded unique structural request")
     41 }
     42 
     43 fn progress(
     44     state: FetchTargetState,
     45     reason: AvailabilityDiscoveryStopReason,
     46     returned: u16,
     47 ) -> AvailabilityDiscoveryProgress {
     48     AvailabilityDiscoveryProgress::new(
     49         AvailabilityDiscoveryState::Requested(state),
     50         reason,
     51         returned,
     52     )
     53     .expect("consistent bounded target progress")
     54 }
     55 
     56 fn not_requested() -> AvailabilityDiscoveryProgress {
     57     AvailabilityDiscoveryProgress::new(
     58         AvailabilityDiscoveryState::NotRequested,
     59         AvailabilityDiscoveryStopReason::None,
     60         0,
     61     )
     62     .expect("explicit unrequested stream")
     63 }
     64 
     65 fn target(
     66     id: TargetFingerprint,
     67     listings: AvailabilityDiscoveryProgress,
     68     profiles: AvailabilityDiscoveryProgress,
     69     deletions: AvailabilityDiscoveryProgress,
     70 ) -> AvailabilityDiscoveryTargetOutcome {
     71     AvailabilityDiscoveryTargetOutcome::new(id, listings, profiles, deletions)
     72         .expect("one shared bounded target allowance")
     73 }
     74 
     75 fn unrequested_target(index: u8) -> AvailabilityDiscoveryTargetOutcome {
     76     target(
     77         fingerprint(index),
     78         not_requested(),
     79         not_requested(),
     80         not_requested(),
     81     )
     82 }
     83 
     84 fn usage(calls: u8, returned: u16) -> AvailabilityDiscoveryUsage {
     85     AvailabilityDiscoveryUsage::new(calls, returned).expect("bounded supplied operation accounting")
     86 }
     87 
     88 fn assert_code(error: SafeError, code: SafeErrorCode) {
     89     assert_eq!(error.code(), code);
     90     let standard_error: &dyn Error = &error;
     91     assert!(standard_error.source().is_none());
     92 }
     93 
     94 #[test]
     95 fn request_admits_empty_and_exact_target_limit() {
     96     assert_eq!(MAX_DISCOVERY_TARGETS, 16);
     97     for count in [0, 1, 16] {
     98         let targets: Vec<_> = (1..=count).map(fingerprint).collect();
     99         let pointer = targets.as_ptr();
    100         let expected: Vec<_> = targets
    101             .iter()
    102             .map(|value| value.as_str().to_owned())
    103             .collect();
    104         let value = request(targets);
    105         assert_eq!(value.targets().len(), usize::from(count));
    106         assert_eq!(value.targets().as_ptr(), pointer);
    107         assert_eq!(
    108             value
    109                 .targets()
    110                 .iter()
    111                 .map(TargetFingerprint::as_str)
    112                 .collect::<Vec<_>>(),
    113             expected
    114         );
    115     }
    116     assert_code(
    117         AvailabilityDiscoveryRequest::new(
    118             RequestId::new(7).expect("request"),
    119             scope(),
    120             (1..=17).map(fingerprint).collect(),
    121             1,
    122         )
    123         .expect_err("seventeen selected targets"),
    124         SafeErrorCode::AvailabilityCapacity,
    125     );
    126 }
    127 
    128 #[test]
    129 fn request_refuses_duplicates_and_invalid_deadlines() {
    130     for targets in [
    131         vec![fingerprint(1), fingerprint(1)],
    132         vec![
    133             fingerprint(1),
    134             fingerprint(2),
    135             fingerprint(3),
    136             fingerprint(1),
    137         ],
    138     ] {
    139         assert_code(
    140             AvailabilityDiscoveryRequest::new(
    141                 RequestId::new(7).expect("request"),
    142                 scope(),
    143                 targets,
    144                 1,
    145             )
    146             .expect_err("duplicate canonical target"),
    147             SafeErrorCode::AvailabilityInvalidInput,
    148         );
    149     }
    150     let uppercase = TargetFingerprint::parse("AB".repeat(32)).expect("shared canonicalization");
    151     let lowercase = TargetFingerprint::parse("ab".repeat(32)).expect("canonical target");
    152     assert_eq!(uppercase.as_str(), "ab".repeat(32));
    153     assert_code(
    154         AvailabilityDiscoveryRequest::new(
    155             RequestId::new(7).expect("request"),
    156             scope(),
    157             vec![uppercase, lowercase],
    158             1,
    159         )
    160         .expect_err("canonical aliases are duplicate targets"),
    161         SafeErrorCode::AvailabilityInvalidInput,
    162     );
    163     for deadline in [1, 30_000] {
    164         assert_eq!(
    165             AvailabilityDiscoveryRequest::new(
    166                 RequestId::new(7).expect("request"),
    167                 scope(),
    168                 vec![],
    169                 deadline
    170             )
    171             .expect("exact allowed deadline")
    172             .deadline_millis(),
    173             deadline
    174         );
    175     }
    176     for deadline in [0, 30_001, u64::MAX] {
    177         assert_code(
    178             AvailabilityDiscoveryRequest::new(
    179                 RequestId::new(7).expect("request"),
    180                 scope(),
    181                 vec![],
    182                 deadline,
    183             )
    184             .expect_err("outside absolute deadline range"),
    185             SafeErrorCode::AvailabilityInvalidInput,
    186         );
    187     }
    188 }
    189 
    190 #[test]
    191 fn request_preserves_scope_and_request_without_signer() {
    192     let value = AvailabilityDiscoveryRequest::new(
    193         RequestId::new(u64::MAX).expect("full-width request"),
    194         scope(),
    195         vec![fingerprint(1)],
    196         30_000,
    197     )
    198     .expect("pure structural values require no signing capability");
    199     assert_eq!(value.request_id().get(), u64::MAX);
    200     assert_eq!(value.scope().owner().to_hex(), AUTHOR_HEX);
    201     assert_eq!(value.scope().context().context_id(), &[1; 32]);
    202     assert_eq!(value.scope().context().store_generation(), &[2; 32]);
    203     assert_eq!(value.scope().context().source_revision(), u64::MAX);
    204     assert_eq!(value.scope().context().projection_generation(), u64::MAX);
    205     assert_eq!(value.scope().session_generation().value(), u64::MAX);
    206     assert_eq!(value.deadline_millis(), 30_000);
    207     let value = AvailabilityDiscoveryOutcome::new(
    208         value,
    209         usage(0, 0),
    210         vec![unrequested_target(1)],
    211         Vec::<u8>::new(),
    212     )
    213     .expect("structural unrequested outcome");
    214     assert_eq!(value.request().request_id().get(), u64::MAX);
    215     assert_eq!(
    216         value.request().scope().context().projection_generation(),
    217         u64::MAX
    218     );
    219 }
    220 
    221 #[test]
    222 fn progress_preserves_every_shared_state_and_empty_distinction() {
    223     let unrequested = not_requested();
    224     assert_eq!(
    225         unrequested.state(),
    226         AvailabilityDiscoveryState::NotRequested
    227     );
    228     assert_eq!(unrequested.reason(), AvailabilityDiscoveryStopReason::None);
    229     assert_eq!(unrequested.returned(), 0);
    230     let cases = [
    231         (
    232             FetchTargetState::Complete,
    233             AvailabilityDiscoveryStopReason::None,
    234         ),
    235         (
    236             FetchTargetState::Partial,
    237             AvailabilityDiscoveryStopReason::None,
    238         ),
    239         (
    240             FetchTargetState::Partial,
    241             AvailabilityDiscoveryStopReason::BudgetExhausted,
    242         ),
    243         (
    244             FetchTargetState::Partial,
    245             AvailabilityDiscoveryStopReason::DeadlineExpired,
    246         ),
    247         (
    248             FetchTargetState::Unavailable,
    249             AvailabilityDiscoveryStopReason::None,
    250         ),
    251         (
    252             FetchTargetState::FailedRetryable,
    253             AvailabilityDiscoveryStopReason::None,
    254         ),
    255         (
    256             FetchTargetState::FailedTerminal,
    257             AvailabilityDiscoveryStopReason::None,
    258         ),
    259         (
    260             FetchTargetState::Cancelled,
    261             AvailabilityDiscoveryStopReason::Stopped,
    262         ),
    263     ];
    264     for (state, reason) in cases {
    265         let value = progress(state, reason, 0);
    266         assert_eq!(value.state(), AvailabilityDiscoveryState::Requested(state));
    267         assert_eq!(value.reason(), reason);
    268         assert_eq!(value.returned(), 0);
    269         assert_ne!(value.state(), unrequested.state());
    270         if state != FetchTargetState::Unavailable {
    271             for count in [1, 64] {
    272                 assert_eq!(progress(state, reason, count).returned(), count);
    273             }
    274         }
    275     }
    276     assert_ne!(
    277         progress(
    278             FetchTargetState::Complete,
    279             AvailabilityDiscoveryStopReason::None,
    280             0
    281         )
    282         .state(),
    283         progress(
    284             FetchTargetState::Unavailable,
    285             AvailabilityDiscoveryStopReason::None,
    286             0
    287         )
    288         .state()
    289     );
    290 }
    291 
    292 #[test]
    293 fn progress_rejects_inconsistent_stop_reasons_and_counts() {
    294     let states = [
    295         AvailabilityDiscoveryState::NotRequested,
    296         AvailabilityDiscoveryState::Requested(FetchTargetState::Complete),
    297         AvailabilityDiscoveryState::Requested(FetchTargetState::Partial),
    298         AvailabilityDiscoveryState::Requested(FetchTargetState::Unavailable),
    299         AvailabilityDiscoveryState::Requested(FetchTargetState::FailedRetryable),
    300         AvailabilityDiscoveryState::Requested(FetchTargetState::FailedTerminal),
    301         AvailabilityDiscoveryState::Requested(FetchTargetState::Cancelled),
    302     ];
    303     for state in states {
    304         for reason in [
    305             AvailabilityDiscoveryStopReason::None,
    306             AvailabilityDiscoveryStopReason::BudgetExhausted,
    307             AvailabilityDiscoveryStopReason::DeadlineExpired,
    308             AvailabilityDiscoveryStopReason::Stopped,
    309         ] {
    310             for count in [0, 1, 64, 65] {
    311                 let valid = match state {
    312                     AvailabilityDiscoveryState::NotRequested => {
    313                         reason == AvailabilityDiscoveryStopReason::None && count == 0
    314                     }
    315                     AvailabilityDiscoveryState::Requested(
    316                         FetchTargetState::Complete
    317                         | FetchTargetState::FailedRetryable
    318                         | FetchTargetState::FailedTerminal,
    319                     ) => reason == AvailabilityDiscoveryStopReason::None,
    320                     AvailabilityDiscoveryState::Requested(FetchTargetState::Partial) => {
    321                         reason != AvailabilityDiscoveryStopReason::Stopped
    322                     }
    323                     AvailabilityDiscoveryState::Requested(FetchTargetState::Unavailable) => {
    324                         reason == AvailabilityDiscoveryStopReason::None && count == 0
    325                     }
    326                     AvailabilityDiscoveryState::Requested(FetchTargetState::Cancelled) => {
    327                         reason == AvailabilityDiscoveryStopReason::Stopped
    328                     }
    329                 };
    330                 let result = AvailabilityDiscoveryProgress::new(state, reason, count);
    331                 if count > 64 {
    332                     assert_code(
    333                         result.expect_err("returned cap checked first"),
    334                         SafeErrorCode::AvailabilityCapacity,
    335                     );
    336                 } else if valid {
    337                     let value = result.expect("admitted state/reason/count matrix entry");
    338                     assert_eq!(
    339                         (value.state(), value.reason(), value.returned()),
    340                         (state, reason, count)
    341                     );
    342                 } else {
    343                     assert_code(
    344                         result.expect_err("inconsistent progress facts"),
    345                         SafeErrorCode::AvailabilityInvalidInput,
    346                     );
    347                 }
    348             }
    349         }
    350     }
    351 }
    352 
    353 #[test]
    354 fn target_streams_remain_independent() {
    355     let listings = progress(
    356         FetchTargetState::Complete,
    357         AvailabilityDiscoveryStopReason::None,
    358         10,
    359     );
    360     let profiles = progress(
    361         FetchTargetState::Partial,
    362         AvailabilityDiscoveryStopReason::DeadlineExpired,
    363         2,
    364     );
    365     let deletions = progress(
    366         FetchTargetState::FailedTerminal,
    367         AvailabilityDiscoveryStopReason::None,
    368         1,
    369     );
    370     let value = target(fingerprint(1), listings, profiles, deletions);
    371     assert_eq!(value.target(), &fingerprint(1));
    372     assert_eq!(value.listings(), listings);
    373     assert_eq!(value.profiles(), profiles);
    374     assert_eq!(value.deletions(), deletions);
    375     assert_eq!(
    376         value.listings().state(),
    377         AvailabilityDiscoveryState::Requested(FetchTargetState::Complete)
    378     );
    379     assert_eq!(
    380         value.profiles().reason(),
    381         AvailabilityDiscoveryStopReason::DeadlineExpired
    382     );
    383     assert_eq!(value.deletions().returned(), 1);
    384 }
    385 
    386 #[test]
    387 fn per_target_limit_is_shared_across_all_three_streams() {
    388     assert_eq!(MAX_DISCOVERY_RETURNED_PER_TARGET, 64);
    389     for counts in [
    390         [0, 0, 0],
    391         [1, 0, 0],
    392         [64, 0, 0],
    393         [0, 64, 0],
    394         [0, 0, 64],
    395         [21, 21, 21],
    396         [22, 21, 21],
    397     ] {
    398         let stages = counts.map(|count| {
    399             progress(
    400                 FetchTargetState::Partial,
    401                 AvailabilityDiscoveryStopReason::None,
    402                 count,
    403             )
    404         });
    405         let value = target(fingerprint(1), stages[0], stages[1], stages[2]);
    406         assert_eq!(
    407             [
    408                 value.listings().returned(),
    409                 value.profiles().returned(),
    410                 value.deletions().returned()
    411             ],
    412             counts
    413         );
    414     }
    415     for counts in [
    416         [23, 21, 21],
    417         [64, 1, 0],
    418         [0, 64, 1],
    419         [1, 0, 64],
    420         [64, 64, 64],
    421     ] {
    422         let stages = counts.map(|count| {
    423             progress(
    424                 FetchTargetState::Partial,
    425                 AvailabilityDiscoveryStopReason::None,
    426                 count,
    427             )
    428         });
    429         assert_code(
    430             AvailabilityDiscoveryTargetOutcome::new(
    431                 fingerprint(1),
    432                 stages[0],
    433                 stages[1],
    434                 stages[2],
    435             )
    436             .expect_err("sum exceeds the one target allowance"),
    437             SafeErrorCode::AvailabilityCapacity,
    438         );
    439     }
    440 }
    441 
    442 #[test]
    443 fn usage_enforces_operation_wide_calls_events_and_no_refunds() {
    444     assert_eq!(MAX_DISCOVERY_FETCH_CALLS, 4);
    445     assert_eq!(MAX_DISCOVERY_RETURNED_EVENTS, 1024);
    446     assert_eq!(DISCOVERY_FETCH_RAW_RESERVATION_BYTES, 8_388_608);
    447     for calls in 0..=4 {
    448         for returned in [0, 1, 1024] {
    449             if calls == 0 && returned > 0 {
    450                 assert_code(
    451                     AvailabilityDiscoveryUsage::new(calls, returned)
    452                         .expect_err("returns without any call"),
    453                     SafeErrorCode::AvailabilityInvalidInput,
    454                 );
    455             } else {
    456                 let value = usage(calls, returned);
    457                 assert_eq!(value.fetch_calls(), calls);
    458                 assert_eq!(value.returned_events(), returned);
    459                 assert_eq!(value.reserved_raw_bytes(), u64::from(calls) * 8_388_608);
    460             }
    461         }
    462     }
    463     assert_eq!(usage(4, 0).reserved_raw_bytes(), 33_554_432);
    464     assert_eq!(
    465         usage(4, 1024).reserved_raw_bytes(),
    466         usage(4, 0).reserved_raw_bytes()
    467     );
    468     for (calls, returned) in [(5, 0), (5, 1024), (4, 1025), (0, 1025), (u8::MAX, u16::MAX)] {
    469         assert_code(
    470             AvailabilityDiscoveryUsage::new(calls, returned).expect_err("aggregate accounting cap"),
    471             SafeErrorCode::AvailabilityCapacity,
    472         );
    473     }
    474 }
    475 
    476 #[test]
    477 fn outcome_preserves_items_after_partial_capped_failed_and_cancelled_targets() {
    478     for (state, reason) in [
    479         (
    480             FetchTargetState::Partial,
    481             AvailabilityDiscoveryStopReason::None,
    482         ),
    483         (
    484             FetchTargetState::Partial,
    485             AvailabilityDiscoveryStopReason::BudgetExhausted,
    486         ),
    487         (
    488             FetchTargetState::Partial,
    489             AvailabilityDiscoveryStopReason::DeadlineExpired,
    490         ),
    491         (
    492             FetchTargetState::FailedRetryable,
    493             AvailabilityDiscoveryStopReason::None,
    494         ),
    495         (
    496             FetchTargetState::FailedTerminal,
    497             AvailabilityDiscoveryStopReason::None,
    498         ),
    499         (
    500             FetchTargetState::Cancelled,
    501             AvailabilityDiscoveryStopReason::Stopped,
    502         ),
    503     ] {
    504         let value = AvailabilityDiscoveryOutcome::new(
    505             request(vec![fingerprint(1)]),
    506             usage(1, 3),
    507             vec![target(
    508                 fingerprint(1),
    509                 progress(state, reason, 3),
    510                 not_requested(),
    511                 not_requested(),
    512             )],
    513             vec![11_u8, 22, 33],
    514         )
    515         .expect("valid earlier results survive non-complete target states");
    516         assert_eq!(value.items(), &[11, 22, 33]);
    517         assert_eq!(value.usage().returned_events(), 3);
    518         assert_eq!(
    519             value.listings_state(),
    520             AvailabilityDiscoveryState::Requested(state)
    521         );
    522         assert_eq!(value.targets()[0].listings().reason(), reason);
    523         assert_eq!(value.into_items(), vec![11, 22, 33]);
    524     }
    525 }
    526 
    527 #[test]
    528 fn outcome_refuses_missing_extra_and_duplicate_targets() {
    529     for supplied in [
    530         vec![],
    531         vec![unrequested_target(2)],
    532         vec![unrequested_target(1), unrequested_target(2)],
    533     ] {
    534         assert_code(
    535             AvailabilityDiscoveryOutcome::new(
    536                 request(vec![fingerprint(1)]),
    537                 usage(0, 0),
    538                 supplied,
    539                 Vec::<u8>::new(),
    540             )
    541             .expect_err("missing or unrequested target fingerprint"),
    542             SafeErrorCode::AvailabilityScopeMismatch,
    543         );
    544     }
    545     assert_code(
    546         AvailabilityDiscoveryOutcome::new(
    547             request(vec![fingerprint(1), fingerprint(2)]),
    548             usage(0, 0),
    549             vec![unrequested_target(1), unrequested_target(1)],
    550             Vec::<u8>::new(),
    551         )
    552         .expect_err("duplicate supplied outcome"),
    553         SafeErrorCode::AvailabilityInvalidInput,
    554     );
    555     assert_code(
    556         AvailabilityDiscoveryOutcome::new(
    557             request((1..=16).map(fingerprint).collect()),
    558             usage(0, 0),
    559             (1..=17).map(unrequested_target).collect(),
    560             Vec::<u8>::new(),
    561         )
    562         .expect_err("target cap before set validation"),
    563         SafeErrorCode::AvailabilityCapacity,
    564     );
    565     let value = AvailabilityDiscoveryOutcome::new(
    566         request(vec![fingerprint(1), fingerprint(2), fingerprint(3)]),
    567         usage(0, 0),
    568         vec![
    569             unrequested_target(3),
    570             unrequested_target(1),
    571             unrequested_target(2),
    572         ],
    573         Vec::<u8>::new(),
    574     )
    575     .expect("permuted exact fingerprint set");
    576     assert_eq!(
    577         value
    578             .targets()
    579             .iter()
    580             .map(|value| value.target().as_str())
    581             .collect::<Vec<_>>(),
    582         vec![
    583             format!("{:064x}", 3),
    584             format!("{:064x}", 1),
    585             format!("{:064x}", 2)
    586         ]
    587     );
    588 }
    589 
    590 #[test]
    591 fn outcome_binds_returned_count_and_valid_item_count() {
    592     for retained in [0, 1, 3] {
    593         let value = AvailabilityDiscoveryOutcome::new(
    594             request(vec![fingerprint(1)]),
    595             usage(1, 3),
    596             vec![target(
    597                 fingerprint(1),
    598                 progress(
    599                     FetchTargetState::Partial,
    600                     AvailabilityDiscoveryStopReason::None,
    601                     3,
    602                 ),
    603                 not_requested(),
    604                 not_requested(),
    605             )],
    606             vec![9_u8; retained],
    607         )
    608         .expect("valid items may be fewer than returned candidates");
    609         assert_eq!(value.items().len(), retained);
    610     }
    611     for returned in [0, 2, 4] {
    612         assert_code(
    613             AvailabilityDiscoveryOutcome::new(
    614                 request(vec![fingerprint(1)]),
    615                 usage(1, returned),
    616                 vec![target(
    617                     fingerprint(1),
    618                     progress(
    619                         FetchTargetState::Partial,
    620                         AvailabilityDiscoveryStopReason::None,
    621                         3,
    622                     ),
    623                     not_requested(),
    624                     not_requested(),
    625                 )],
    626                 Vec::<u8>::new(),
    627             )
    628             .expect_err("exact aggregate returned count"),
    629             SafeErrorCode::AvailabilityInvalidInput,
    630         );
    631     }
    632     assert_code(
    633         AvailabilityDiscoveryOutcome::new(
    634             request(vec![fingerprint(1)]),
    635             usage(1, 3),
    636             vec![target(
    637                 fingerprint(1),
    638                 progress(
    639                     FetchTargetState::Partial,
    640                     AvailabilityDiscoveryStopReason::None,
    641                     3,
    642                 ),
    643                 not_requested(),
    644                 not_requested(),
    645             )],
    646             vec![9_u8; 4],
    647         )
    648         .expect_err("valid items cannot exceed returned candidates"),
    649         SafeErrorCode::AvailabilityInvalidInput,
    650     );
    651     assert_code(
    652         AvailabilityDiscoveryOutcome::new(request(vec![]), usage(0, 0), vec![], vec![9_u8; 1025])
    653             .expect_err("item cap before empty-source/count validation"),
    654         SafeErrorCode::AvailabilityCapacity,
    655     );
    656     assert_code(
    657         AvailabilityDiscoveryOutcome::new(
    658             request(vec![fingerprint(1)]),
    659             usage(0, 0),
    660             vec![target(
    661                 fingerprint(1),
    662                 progress(
    663                     FetchTargetState::Complete,
    664                     AvailabilityDiscoveryStopReason::None,
    665                     0,
    666                 ),
    667                 not_requested(),
    668                 not_requested(),
    669             )],
    670             Vec::<u8>::new(),
    671         )
    672         .expect_err("completion requires a supplied fetch call"),
    673         SafeErrorCode::AvailabilityInvalidInput,
    674     );
    675 }
    676 
    677 #[test]
    678 fn empty_selection_never_fabricates_complete_or_network_work() {
    679     let value =
    680         AvailabilityDiscoveryOutcome::new(request(vec![]), usage(0, 0), vec![], Vec::<u8>::new())
    681             .expect("explicit no-source selection");
    682     assert_eq!(
    683         value.listings_state(),
    684         AvailabilityDiscoveryState::NotRequested
    685     );
    686     assert_eq!(
    687         value.profiles_state(),
    688         AvailabilityDiscoveryState::NotRequested
    689     );
    690     assert_eq!(
    691         value.deletions_state(),
    692         AvailabilityDiscoveryState::NotRequested
    693     );
    694     assert_eq!(value.usage().reserved_raw_bytes(), 0);
    695     assert!(value.targets().is_empty());
    696     assert!(value.items().is_empty());
    697     for (calls, returned, items) in [
    698         (1, 0, vec![]),
    699         (1, 1, vec![]),
    700         (1, 1, vec![1_u8]),
    701         (0, 0, vec![1_u8]),
    702     ] {
    703         assert_code(
    704             AvailabilityDiscoveryOutcome::new(
    705                 request(vec![]),
    706                 usage(calls, returned),
    707                 vec![],
    708                 items,
    709             )
    710             .expect_err("empty selection cannot fabricate work or items"),
    711             SafeErrorCode::AvailabilityInvalidInput,
    712         );
    713     }
    714     assert_code(
    715         AvailabilityDiscoveryOutcome::new(
    716             request(vec![]),
    717             usage(0, 0),
    718             vec![unrequested_target(1)],
    719             Vec::<u8>::new(),
    720         )
    721         .expect_err("no target may be fabricated"),
    722         SafeErrorCode::AvailabilityScopeMismatch,
    723     );
    724 }
    725 
    726 #[test]
    727 fn stream_completeness_requires_every_selected_target() {
    728     let states = [
    729         AvailabilityDiscoveryState::NotRequested,
    730         AvailabilityDiscoveryState::Requested(FetchTargetState::Complete),
    731         AvailabilityDiscoveryState::Requested(FetchTargetState::Partial),
    732         AvailabilityDiscoveryState::Requested(FetchTargetState::Unavailable),
    733         AvailabilityDiscoveryState::Requested(FetchTargetState::FailedRetryable),
    734         AvailabilityDiscoveryState::Requested(FetchTargetState::FailedTerminal),
    735         AvailabilityDiscoveryState::Requested(FetchTargetState::Cancelled),
    736     ];
    737     for first in states {
    738         for second in states {
    739             let stage = |state| {
    740                 AvailabilityDiscoveryProgress::new(
    741                     state,
    742                     if state == AvailabilityDiscoveryState::Requested(FetchTargetState::Cancelled) {
    743                         AvailabilityDiscoveryStopReason::Stopped
    744                     } else {
    745                         AvailabilityDiscoveryStopReason::None
    746                     },
    747                     0,
    748                 )
    749                 .expect("zero-count stream state")
    750             };
    751             let value = AvailabilityDiscoveryOutcome::new(
    752                 request(vec![fingerprint(1), fingerprint(2)]),
    753                 usage(1, 0),
    754                 vec![
    755                     target(fingerprint(1), stage(first), stage(first), stage(first)),
    756                     target(fingerprint(2), stage(second), stage(second), stage(second)),
    757                 ],
    758                 Vec::<u8>::new(),
    759             )
    760             .expect("exact selected stream evidence");
    761             let expected = if first == second {
    762                 first
    763             } else {
    764                 AvailabilityDiscoveryState::Requested(FetchTargetState::Partial)
    765             };
    766             assert_eq!(value.listings_state(), expected);
    767             assert_eq!(value.profiles_state(), expected);
    768             assert_eq!(value.deletions_state(), expected);
    769         }
    770     }
    771 }
    772 
    773 #[test]
    774 fn one_stream_failure_never_erases_another_stream_completion() {
    775     for interrupted in [
    776         FetchTargetState::Partial,
    777         FetchTargetState::Unavailable,
    778         FetchTargetState::FailedRetryable,
    779         FetchTargetState::FailedTerminal,
    780         FetchTargetState::Cancelled,
    781     ] {
    782         let reason = if interrupted == FetchTargetState::Cancelled {
    783             AvailabilityDiscoveryStopReason::Stopped
    784         } else {
    785             AvailabilityDiscoveryStopReason::None
    786         };
    787         for stream in 0..3 {
    788             let mut stages = [progress(
    789                 FetchTargetState::Complete,
    790                 AvailabilityDiscoveryStopReason::None,
    791                 0,
    792             ); 3];
    793             stages[stream] = progress(interrupted, reason, 0);
    794             let value = AvailabilityDiscoveryOutcome::new(
    795                 request(vec![fingerprint(1)]),
    796                 usage(1, 0),
    797                 vec![target(fingerprint(1), stages[0], stages[1], stages[2])],
    798                 Vec::<u8>::new(),
    799             )
    800             .expect("independent stream statuses");
    801             for (index, observed) in [
    802                 value.listings_state(),
    803                 value.profiles_state(),
    804                 value.deletions_state(),
    805             ]
    806             .into_iter()
    807             .enumerate()
    808             {
    809                 assert_eq!(
    810                     observed,
    811                     AvailabilityDiscoveryState::Requested(if index == stream {
    812                         interrupted
    813                     } else {
    814                         FetchTargetState::Complete
    815                     })
    816                 );
    817             }
    818         }
    819     }
    820 }
    821 
    822 #[test]
    823 fn outcome_retains_owned_nonclone_items_without_copy() {
    824     struct PrivateItem {
    825         marker: String,
    826     }
    827     let items = vec![PrivateItem {
    828         marker: "HCAV_PRIVATE_NONDEBUG_ITEM".to_owned(),
    829     }];
    830     let pointer = items.as_ptr();
    831     let capacity = items.capacity();
    832     let targets = vec![target(
    833         fingerprint(1),
    834         progress(
    835             FetchTargetState::FailedRetryable,
    836             AvailabilityDiscoveryStopReason::None,
    837             1,
    838         ),
    839         not_requested(),
    840         not_requested(),
    841     )];
    842     let targets_pointer = targets.as_ptr();
    843     let value = AvailabilityDiscoveryOutcome::new(
    844         request(vec![fingerprint(1)]),
    845         usage(1, 1),
    846         targets,
    847         items,
    848     )
    849     .expect("no item Clone/Debug requirement");
    850     assert_eq!(value.items().as_ptr(), pointer);
    851     assert_eq!(value.targets().as_ptr(), targets_pointer);
    852     assert_eq!(value.items()[0].marker, "HCAV_PRIVATE_NONDEBUG_ITEM");
    853     assert!(!format!("{value:?}").contains("HCAV_PRIVATE_NONDEBUG_ITEM"));
    854     assert!(!value.metadata_json().contains("HCAV_PRIVATE_NONDEBUG_ITEM"));
    855     let returned = value.into_items();
    856     assert_eq!(returned.as_ptr(), pointer);
    857     assert_eq!(returned.capacity(), capacity);
    858     assert_eq!(returned[0].marker, "HCAV_PRIVATE_NONDEBUG_ITEM");
    859 }
    860 
    861 #[test]
    862 fn metadata_serialization_has_exact_safe_schema() {
    863     let value = AvailabilityDiscoveryOutcome::new(
    864         request(vec![fingerprint(1)]),
    865         usage(1, 3),
    866         vec![target(
    867             fingerprint(1),
    868             progress(
    869                 FetchTargetState::Complete,
    870                 AvailabilityDiscoveryStopReason::None,
    871                 1,
    872             ),
    873             progress(
    874                 FetchTargetState::Partial,
    875                 AvailabilityDiscoveryStopReason::BudgetExhausted,
    876                 2,
    877             ),
    878             not_requested(),
    879         )],
    880         vec!["HCAV_PRIVATE_ITEM_PAYLOAD"],
    881     )
    882     .expect("independently described metadata fixture");
    883     let expected = concat!(
    884         "{\"version\":1,\"fetch_calls\":1,\"reserved_raw_bytes\":8388608,\"returned_events\":3,\"retained_items\":1,",
    885         "\"listings\":\"complete\",\"profiles\":\"partial\",\"deletions\":\"not_requested\",\"targets\":[",
    886         "{\"target\":\"0000000000000000000000000000000000000000000000000000000000000001\",",
    887         "\"listings\":{\"state\":\"complete\",\"reason\":\"none\",\"returned\":1},",
    888         "\"profiles\":{\"state\":\"partial\",\"reason\":\"budget_exhausted\",\"returned\":2},",
    889         "\"deletions\":{\"state\":\"not_requested\",\"reason\":\"none\",\"returned\":0}}]}"
    890     );
    891     assert_eq!(value.metadata_json(), expected);
    892     assert_eq!(value.metadata_json(), value.metadata_json());
    893     let empty =
    894         AvailabilityDiscoveryOutcome::new(request(vec![]), usage(0, 0), vec![], Vec::<u8>::new())
    895             .expect("empty metadata");
    896     assert_eq!(
    897         empty.metadata_json(),
    898         "{\"version\":1,\"fetch_calls\":0,\"reserved_raw_bytes\":0,\"returned_events\":0,\"retained_items\":0,\"listings\":\"not_requested\",\"profiles\":\"not_requested\",\"deletions\":\"not_requested\",\"targets\":[]}"
    899     );
    900 }
    901 
    902 #[test]
    903 fn metadata_serialization_is_bounded_at_sixteen_targets() {
    904     assert_eq!(MAX_DISCOVERY_METADATA_BYTES, 16_384);
    905     let targets: Vec<_> = (1..=16)
    906         .rev()
    907         .map(|index| {
    908             target(
    909                 fingerprint(index),
    910                 progress(
    911                     FetchTargetState::Complete,
    912                     AvailabilityDiscoveryStopReason::None,
    913                     32,
    914                 ),
    915                 progress(
    916                     FetchTargetState::Partial,
    917                     AvailabilityDiscoveryStopReason::DeadlineExpired,
    918                     16,
    919                 ),
    920                 progress(
    921                     FetchTargetState::FailedRetryable,
    922                     AvailabilityDiscoveryStopReason::None,
    923                     16,
    924                 ),
    925             )
    926         })
    927         .collect();
    928     let value = AvailabilityDiscoveryOutcome::new(
    929         request((1..=16).map(fingerprint).collect()),
    930         usage(4, 1024),
    931         targets,
    932         vec!["HCAV_PRIVATE_LARGE_RESULT"; 1024],
    933     )
    934     .expect("exact full target/result/accounting bounds");
    935     let json = value.metadata_json();
    936     assert!(json.is_ascii());
    937     assert!(json.len() <= 16_384);
    938     assert_eq!(json.matches("\"target\":").count(), 16);
    939     assert_eq!(json.matches("\"returned\":32").count(), 16);
    940     assert_eq!(json.matches("\"returned\":16").count(), 32);
    941     assert!(json.starts_with("{\"version\":1,\"fetch_calls\":4,\"reserved_raw_bytes\":33554432,\"returned_events\":1024,\"retained_items\":1024,"));
    942     let first = format!("\"target\":\"{:064x}\"", 16);
    943     let last = format!("\"target\":\"{:064x}\"", 1);
    944     assert!(
    945         json.find(&first).expect("supplied first target")
    946             < json.find(&last).expect("supplied last target")
    947     );
    948     assert!(!json.contains("HCAV_PRIVATE_LARGE_RESULT"));
    949     for (state, reason, name, reason_name) in [
    950         (
    951             FetchTargetState::Complete,
    952             AvailabilityDiscoveryStopReason::None,
    953             "complete",
    954             "none",
    955         ),
    956         (
    957             FetchTargetState::Partial,
    958             AvailabilityDiscoveryStopReason::BudgetExhausted,
    959             "partial",
    960             "budget_exhausted",
    961         ),
    962         (
    963             FetchTargetState::Partial,
    964             AvailabilityDiscoveryStopReason::DeadlineExpired,
    965             "partial",
    966             "deadline_expired",
    967         ),
    968         (
    969             FetchTargetState::Unavailable,
    970             AvailabilityDiscoveryStopReason::None,
    971             "unavailable",
    972             "none",
    973         ),
    974         (
    975             FetchTargetState::FailedRetryable,
    976             AvailabilityDiscoveryStopReason::None,
    977             "failed_retryable",
    978             "none",
    979         ),
    980         (
    981             FetchTargetState::FailedTerminal,
    982             AvailabilityDiscoveryStopReason::None,
    983             "failed_terminal",
    984             "none",
    985         ),
    986         (
    987             FetchTargetState::Cancelled,
    988             AvailabilityDiscoveryStopReason::Stopped,
    989             "cancelled",
    990             "stopped",
    991         ),
    992     ] {
    993         let value = AvailabilityDiscoveryOutcome::new(
    994             request(vec![fingerprint(1)]),
    995             usage(1, 0),
    996             vec![target(
    997                 fingerprint(1),
    998                 progress(state, reason, 0),
    999                 not_requested(),
   1000                 not_requested(),
   1001             )],
   1002             Vec::<u8>::new(),
   1003         )
   1004         .expect("every exact metadata state spelling");
   1005         assert!(value.metadata_json().contains(&format!(
   1006             "\"listings\":{{\"state\":\"{name}\",\"reason\":\"{reason_name}\",\"returned\":0}}"
   1007         )));
   1008     }
   1009 }
   1010 
   1011 #[test]
   1012 fn diagnostics_omit_private_payloads_and_remote_messages() {
   1013     struct PrivateItem(&'static str);
   1014     const PRIVATE_MARKER: &str = "HCAV_PRIVATE_PAYLOAD_MARKER";
   1015     const REMOTE_MARKER: &str = "HCAV_HOSTILE_REMOTE_MESSAGE_\"\n\0🥕";
   1016     let shared = FetchTargetOutcome::new(fingerprint(0xab), FetchTargetState::FailedRetryable)
   1017         .with_message(REMOTE_MARKER);
   1018     assert_eq!(shared.message(), Some(REMOTE_MARKER));
   1019     let stage = progress(shared.state(), AvailabilityDiscoveryStopReason::None, 1);
   1020     let target_value = target(
   1021         shared.target().clone(),
   1022         stage,
   1023         not_requested(),
   1024         not_requested(),
   1025     );
   1026     let target_debug = format!("{target_value:?}");
   1027     let requested = request(vec![shared.target().clone()]);
   1028     let request_debug = format!("{requested:?}");
   1029     let value = AvailabilityDiscoveryOutcome::new(
   1030         requested,
   1031         usage(1, 1),
   1032         vec![target_value],
   1033         vec![PrivateItem(PRIVATE_MARKER)],
   1034     )
   1035     .expect("retains only selected shared identity/state facts");
   1036     assert_eq!(value.items()[0].0, PRIVATE_MARKER);
   1037     let context_bytes = format!("{:?}", [1_u8; 32]);
   1038     let store_bytes = format!("{:?}", [2_u8; 32]);
   1039     for diagnostic in [
   1040         request_debug,
   1041         target_debug,
   1042         format!("{value:?}"),
   1043         format!("{stage:?}"),
   1044     ] {
   1045         for forbidden in [
   1046             PRIVATE_MARKER,
   1047             "HCAV_HOSTILE_REMOTE_MESSAGE_",
   1048             AUTHOR_HEX,
   1049             context_bytes.as_str(),
   1050             store_bytes.as_str(),
   1051             shared.target().as_str(),
   1052             "RequestId",
   1053             "request_id",
   1054         ] {
   1055             assert!(!diagnostic.contains(forbidden));
   1056         }
   1057     }
   1058     let json = value.metadata_json();
   1059     assert!(
   1060         json.contains(shared.target().as_str()),
   1061         "metadata admits only the bounded canonical public target identity"
   1062     );
   1063     for forbidden in [
   1064         PRIVATE_MARKER,
   1065         "HCAV_HOSTILE_REMOTE_MESSAGE_",
   1066         AUTHOR_HEX,
   1067         "request_id",
   1068         "context_id",
   1069         "store_generation",
   1070         "scope",
   1071         "message",
   1072         "endpoint",
   1073         "\"events\":",
   1074         "payload",
   1075     ] {
   1076         assert!(!json.contains(forbidden));
   1077     }
   1078 }
   1079 
   1080 #[test]
   1081 fn query_errors_map_to_static_distinct_availability_errors() {
   1082     for (source, expected_code, expected_message) in [
   1083         (
   1084             AvailabilityQueryError::InvalidInput,
   1085             SafeErrorCode::AvailabilityInvalidInput,
   1086             "The availability request is invalid.",
   1087         ),
   1088         (
   1089             AvailabilityQueryError::InputTooLarge,
   1090             SafeErrorCode::AvailabilityInvalidInput,
   1091             "The availability request is invalid.",
   1092         ),
   1093         (
   1094             AvailabilityQueryError::ScopeMismatch,
   1095             SafeErrorCode::AvailabilityScopeMismatch,
   1096             "The availability request belongs to another scope.",
   1097         ),
   1098         (
   1099             AvailabilityQueryError::StaleQuery,
   1100             SafeErrorCode::AvailabilityStaleQuery,
   1101             "The availability query is stale.",
   1102         ),
   1103         (
   1104             AvailabilityQueryError::Capacity,
   1105             SafeErrorCode::AvailabilityCapacity,
   1106             "The availability operation reached its capacity.",
   1107         ),
   1108     ] {
   1109         let value = SafeError::from(source);
   1110         assert_eq!(value.code(), expected_code);
   1111         assert_eq!(value.message().as_str(), expected_message);
   1112         assert_eq!(value.to_string(), expected_message);
   1113     }
   1114 }
   1115 
   1116 #[test]
   1117 fn availability_failures_have_fixed_public_messages() {
   1118     for (source, expected_code, expected_message) in [
   1119         (
   1120             AvailabilityFailure::InvalidInput,
   1121             SafeErrorCode::AvailabilityInvalidInput,
   1122             "The availability request is invalid.",
   1123         ),
   1124         (
   1125             AvailabilityFailure::UnsupportedProfile,
   1126             SafeErrorCode::AvailabilityUnsupportedProfile,
   1127             "This availability profile is unsupported.",
   1128         ),
   1129         (
   1130             AvailabilityFailure::ScopeMismatch,
   1131             SafeErrorCode::AvailabilityScopeMismatch,
   1132             "The availability request belongs to another scope.",
   1133         ),
   1134         (
   1135             AvailabilityFailure::StaleQuery,
   1136             SafeErrorCode::AvailabilityStaleQuery,
   1137             "The availability query is stale.",
   1138         ),
   1139         (
   1140             AvailabilityFailure::Capacity,
   1141             SafeErrorCode::AvailabilityCapacity,
   1142             "The availability operation reached its capacity.",
   1143         ),
   1144         (
   1145             AvailabilityFailure::Unavailable,
   1146             SafeErrorCode::AvailabilityUnavailable,
   1147             "Availability discovery is unavailable.",
   1148         ),
   1149     ] {
   1150         let value = SafeError::from(source);
   1151         assert_eq!(value.code(), expected_code);
   1152         assert_eq!(value.message().as_str(), expected_message);
   1153         assert_eq!(value.to_string(), expected_message);
   1154         assert!(!format!("{value:?}").contains("HCAV_HOSTILE_REMOTE_MESSAGE"));
   1155         let copied = value;
   1156         assert_eq!(copied, value);
   1157         let standard_error: &dyn Error = &value;
   1158         assert!(standard_error.source().is_none());
   1159     }
   1160 }