mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix: close the remaining review findings (cross-process lock, partials)
Second Codex (gpt-6.1-sol, xhigh) pass over 60634d3, each item verified
before fixing:
- new: the sync recheck hashed an existing empty database before schema
setup, so the first sync falsely reported an external change. Hash
after setup; a published snapshot already has the schema and keeps
its bytes.
- sync, import, and entity edits now hold a cross-process lock
(<db>.lock, std File::lock), so a sync cannot replace the database
under an import running in another process. Import validates and
downloads before taking the lock, keeping its error order. MSRV
1.85 -> 1.89 for File::lock.
- the row-count rebuild branch also never downgrades history.
- cache reads no longer delete corrupt entries (a concurrent writer may
have just replaced them); the next put overwrites atomically.
- idx-mcp validates the changes limit before querying and runs each
requested section or analysis once.
- XLSX parsing bounds total cell text, so one large shared string
referenced from many cells cannot exhaust memory.
- PDF/archive percentages must be 0-100%; HHI uses saturating math.
CLI goldens unchanged. Live A/B vs 0.2.4: 16 passed, discover hits the
IDX 403 on both builds (exit 4 vs 1, intended).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
60634d3aef
commit
1e551385d0
10 changed files with 117 additions and 34 deletions
|
|
@ -163,15 +163,18 @@ struct SheetRow {
|
|||
fn row_number(element: &BytesStart<'_>, fallback: usize) -> Result<usize, IdxError> {
|
||||
for attribute in element.attributes() {
|
||||
let attribute = attribute.map_err(|e| xml_error("worksheet", e))?;
|
||||
if attribute.key.local_name().as_ref() == b"r" {
|
||||
if let Ok(number) = String::from_utf8_lossy(&attribute.value).trim().parse() {
|
||||
return Ok(number);
|
||||
}
|
||||
if attribute.key.local_name().as_ref() == b"r"
|
||||
&& let Ok(number) = String::from_utf8_lossy(&attribute.value).trim().parse()
|
||||
{
|
||||
return Ok(number);
|
||||
}
|
||||
}
|
||||
Ok(fallback)
|
||||
}
|
||||
|
||||
/// Total text across all cells of one worksheet; real registers hold a few MB.
|
||||
const MAX_CELL_TEXT_BYTES: usize = 256 * 1024 * 1024;
|
||||
|
||||
fn parse_sheet_rows(xml: &str, shared_strings: &[String]) -> Result<Vec<SheetRow>, IdxError> {
|
||||
let mut reader = Reader::from_str(xml);
|
||||
let mut rows = Vec::new();
|
||||
|
|
@ -179,6 +182,7 @@ fn parse_sheet_rows(xml: &str, shared_strings: &[String]) -> Result<Vec<SheetRow
|
|||
let mut cell: Option<(String, String)> = None;
|
||||
let mut value = String::new();
|
||||
let mut in_value = false;
|
||||
let mut cell_text_bytes = 0usize;
|
||||
|
||||
loop {
|
||||
match reader.read_event() {
|
||||
|
|
@ -231,6 +235,15 @@ fn parse_sheet_rows(xml: &str, shared_strings: &[String]) -> Result<Vec<SheetRow
|
|||
},
|
||||
_ => value.clone(),
|
||||
};
|
||||
// Shared strings are bounded per entry, but one large
|
||||
// string referenced from many cells is copied each time.
|
||||
cell_text_bytes += text.len();
|
||||
if cell_text_bytes > MAX_CELL_TEXT_BYTES {
|
||||
return Err(xml_error(
|
||||
"worksheet",
|
||||
format!("cell text exceeds {MAX_CELL_TEXT_BYTES} bytes"),
|
||||
));
|
||||
}
|
||||
current_row.cells.insert(column, text);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue