corpus-core: make the stream contract hold under hostile input

This commit is contained in:
funkpower
2026-09-19 11:11:58 -04:00
parent 6c2f5352a0
commit 6d9b7415dd
14 changed files with 593 additions and 85 deletions
+32
View File
@@ -22,8 +22,18 @@ pub struct Hit {
/// Position within the channel's own ranking, from one.
pub rank: u32,
/// The channel's raw score, on whatever scale that channel uses.
#[serde(
serialize_with = "crate::float::serialize",
deserialize_with = "crate::float::deserialize"
)]
pub score: f64,
/// Anything the producer wants to carry through fusion untouched.
///
/// Keys serialise in sorted order, which is what makes a fused stream
/// byte-reproducible. That holds because `serde_json`'s map is a
/// `BTreeMap`; enabling its `preserve_order` feature anywhere in the
/// dependency graph would switch it to insertion order and break it. The
/// test below is what would catch that.
#[serde(default)]
pub payload: Map<String, Value>,
}
@@ -42,6 +52,12 @@ impl Hit {
}
}
impl crate::Record for Hit {
fn version(&self) -> u32 {
self.v
}
}
/// A retrieval channel.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
@@ -80,6 +96,22 @@ mod tests {
);
}
#[test]
fn a_score_that_is_not_a_number_is_refused_rather_than_written_as_null() {
let mut hit = Hit::new("a", Channel::Fts, 1, 0.0);
for bad in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
hit.score = bad;
let e = serde_json::to_string(&hit).unwrap_err();
assert!(e.to_string().contains("cannot be written"), "{bad}: {e}");
}
}
#[test]
fn a_score_that_overflows_a_float_is_refused_on_the_way_in() {
let line = r#"{"id":"a","channel":"fts","rank":1,"score":1e999}"#;
assert!(serde_json::from_str::<Hit>(line).is_err());
}
#[test]
fn payload_keys_serialise_in_a_fixed_order() {
let mut hit = Hit::new("abc", Channel::Vector, 2, 0.25);