fix(sync): releases record stored rows; oversized manifests are errors

From the Codex re-gate of the 0.3.3 fixes:
- Imports recorded row_count as the rows parsed, but INSERT OR IGNORE
  drops a file's repeated ticker/investor rows, so the count could exceed
  what is stored, and the new stored-row validation would then reject a
  snapshot the publisher built from such a file. Record the rows stored.
- A local manifest over the 1 MiB limit was read truncated rather than
  rejected; read one byte more and fail when it does not fit.
- The backup-recovery test also passed on the old code; it now fails an
  install after the leftover backup was found and checks the old data is
  back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
hermes 2026-10-17 05:10:18 +00:00
commit b472d76e27
2 changed files with 71 additions and 7 deletions

View file

@ -355,7 +355,13 @@ pub fn write_ksei_release(
}
let inserted = insert_ksei_holdings_rows(conn, holdings)?;
let _ = insert_release(conn, release)?;
// Record the rows stored, not parsed: INSERT OR IGNORE drops repeated
// ticker/investor rows, and snapshot validation counts what is stored.
let stored = OwnershipRelease {
row_count: inserted,
..release.clone()
};
let _ = insert_release(conn, &stored)?;
Ok(inserted)
})();
@ -1616,6 +1622,38 @@ mod tests {
);
}
#[test]
fn a_release_records_the_rows_it_stored() {
// A file listing the same ticker/investor twice stores one row; the
// release metadata must say 1, or snapshot validation rejects it.
let conn = setup();
let bbca = upsert_ticker(&conn, "BBCA", None).unwrap();
write_release(
&conn,
"dup",
"2026-02-27",
1,
bbca,
&[(None, "ALPHA", 1000), (None, "ALPHA", 1000)],
);
let row_count: i64 = conn
.query_row(
"SELECT row_count FROM ownership_releases WHERE sha256 = 'dup'",
[],
|row| row.get(0),
)
.unwrap();
let stored: i64 = conn
.query_row(
"SELECT COUNT(*) FROM ksei_holdings WHERE release_sha256 = 'dup'",
[],
|row| row.get(0),
)
.unwrap();
assert_eq!((row_count, stored), (1, 1));
}
#[test]
fn changes_reject_a_date_without_a_release() {
let conn = setup();