Peer code review found multiple panic-reachable paths: 1. serde_json::to_string().unwrap() in 4 robot-mode output functions (who.rs, main.rs x3). If serialization ever failed (e.g., NaN from edge-case division), the CLI would panic with an unhelpful stack trace. Replaced with unwrap_or_else that emits a structured JSON error fallback. 2. encode_rowid() in chunk_ids.rs used unchecked multiplication (document_id * 1000). On extreme document IDs this could silently wrap in release mode, causing embedding rowid collisions. Now uses checked_mul + checked_add with a diagnostic panic message. 3. HTTP response body truncation at byte index 500 in client.rs could split a multi-byte UTF-8 character, causing a panic. Now uses floor_char_boundary(500) for safe truncation. 4. who.rs reviews mode: SQL used `m.author_username != ?1` which silently dropped MRs with NULL author_username (SQL NULL != anything = NULL). Changed to `(m.author_username IS NULL OR m.author_username != ?1)` to match the pattern already used in expert mode. 5. handle_auth_test hardcoded exit code 5 for all errors regardless of type. Config not found (20), token not set (4), and network errors (8) all incorrectly returned 5. Now uses e.exit_code() from the actual LoreError, with proper suggestion hints in human mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
63 lines
1.7 KiB
Rust
63 lines
1.7 KiB
Rust
pub const CHUNK_ROWID_MULTIPLIER: i64 = 1000;
|
|
|
|
pub fn encode_rowid(document_id: i64, chunk_index: i64) -> i64 {
|
|
document_id
|
|
.checked_mul(CHUNK_ROWID_MULTIPLIER)
|
|
.and_then(|v| v.checked_add(chunk_index))
|
|
.unwrap_or_else(|| {
|
|
panic!("encode_rowid overflow: document_id={document_id}, chunk_index={chunk_index}")
|
|
})
|
|
}
|
|
|
|
pub fn decode_rowid(rowid: i64) -> (i64, i64) {
|
|
let document_id = rowid / CHUNK_ROWID_MULTIPLIER;
|
|
let chunk_index = rowid % CHUNK_ROWID_MULTIPLIER;
|
|
(document_id, chunk_index)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_encode_single_chunk() {
|
|
assert_eq!(encode_rowid(1, 0), 1000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_encode_multi_chunk() {
|
|
assert_eq!(encode_rowid(1, 5), 1005);
|
|
}
|
|
|
|
#[test]
|
|
fn test_encode_specific_values() {
|
|
assert_eq!(encode_rowid(42, 0), 42000);
|
|
assert_eq!(encode_rowid(42, 5), 42005);
|
|
}
|
|
|
|
#[test]
|
|
fn test_decode_zero_chunk() {
|
|
assert_eq!(decode_rowid(42000), (42, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_decode_roundtrip() {
|
|
for doc_id in [0, 1, 42, 100, 999, 10000] {
|
|
for chunk_idx in [0, 1, 5, 99, 999] {
|
|
let rowid = encode_rowid(doc_id, chunk_idx);
|
|
let (decoded_doc, decoded_chunk) = decode_rowid(rowid);
|
|
assert_eq!(
|
|
(decoded_doc, decoded_chunk),
|
|
(doc_id, chunk_idx),
|
|
"Roundtrip failed for doc_id={doc_id}, chunk_idx={chunk_idx}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiplier_value() {
|
|
assert_eq!(CHUNK_ROWID_MULTIPLIER, 1000);
|
|
}
|
|
}
|