{"record":{"id":"704e407b22c16c9b","repo":"astrid-runtime/astrid","slug":"frozen-search-shape-deserializes","errorCode":null,"errorMessage":"frozen search shape deserializes","messagePattern":"frozen search shape deserializes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-gateway/src/routes/sessions_tests.rs","lineNumber":679,"sourceCode":"}\n\n#[test]\nfn parse_search_response_round_trips_frozen_shape() {\n    let body = serde_json::json!({\n        \"correlation_id\": \"c\",\n        \"results\": [\n            {\n                \"session_id\": \"s1\",\n                \"title\": \"Trip planning\",\n                \"snippet\": \"…book the flight…\",\n                \"match_count\": 2,\n                \"updated_at\": 1_719_000_000_i64\n            },\n            { \"session_id\": \"s2\", \"match_count\": 1 }\n        ],\n        \"next_cursor\": \"page-2\"\n    });\n    let parsed = parse_search_response(body).expect(\"frozen search shape deserializes\");\n    assert_eq!(parsed.results.len(), 2);\n    assert_eq!(parsed.next_cursor.as_deref(), Some(\"page-2\"));\n    let first = &parsed.results[0];\n    assert_eq!(first.session_id, \"s1\");\n    assert_eq!(first.title.as_deref(), Some(\"Trip planning\"));\n    assert_eq!(first.match_count, 2);\n    assert_eq!(first.updated_at, Some(1_719_000_000));\n    let second = &parsed.results[1];\n    assert!(second.title.is_none());\n    assert!(second.snippet.is_none());\n    assert!(second.updated_at.is_none());\n    assert_eq!(second.match_count, 1);\n}\n\n#[test]\nfn parse_search_response_null_next_cursor_is_last_page() {\n    let body = serde_json::json!({ \"results\": [], \"next_cursor\": null });\n    let parsed = parse_search_response(body).expect(\"empty page deserializes\");","sourceCodeStart":661,"sourceCodeEnd":697,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/routes/sessions_tests.rs#L661-L697","documentation":"parse_search_response_round_trips_frozen_shape deserializes a frozen search-response JSON (results array with session_id/title/match_count/updated_at and next_cursor) via parse_search_response, expecting success. A panic means the search response shape drifted from the frozen contract the test pins.","triggerScenarios":"Changing SearchResponse/its result item fields or types (results, next_cursor, session_id, title, match_count, updated_at) so the frozen body fails to deserialize in parse_search_response.","commonSituations":"Renaming next_cursor or results; changing match_count type; adding a required field to search result items; cursor encoding changes reflected in the deserializer.","solutions":["Update parse_search_response (or revert the response change) so it matches the frozen shape","Adjust the frozen fixture only as part of a deliberate, documented schema change","Log the serde error from the failing parse to pinpoint the mismatched field","Keep search response pagination fields (next_cursor) backward compatible"],"exampleFix":"// before\npub nextCursor: Option<String>,\n// after\n#[serde(rename = \"next_cursor\")]\npub next_cursor: Option<String>,","handlingStrategy":"try-catch","validationCode":"assert!(body.get(\"results\").map_or(false, serde_json::Value::is_array),\n    \"search reply missing results array\");","typeGuard":"fn is_search_reply(v: &serde_json::Value) -> bool {\n    v.get(\"results\").map_or(false, serde_json::Value::is_array)\n}","tryCatchPattern":"let parsed = parse_search_response(&body)\n    .unwrap_or_else(|e| panic!(\"frozen search shape deserializes: {e}; body={body}\"));","preventionTips":["Pin the search wire shape with this frozen fixture and keep it in CI","Rename pagination fields only with a documented schema bump","Include the raw body in parser error messages for fast diagnosis"],"tags":["tests","json","search","schema"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}