| author | |
| committer | |
| log | 1cec85d1bb8078889dab2f72485b2407ee2d2de3 |
| tree | 9da294f044232b3048ed664f957d46ff5fcdd313 |
| parent | 4ea1421ffb1f6c887df24f9c459c933ddcc4df68 |
| signature | Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU (~clover) |
Retain the established append behavior when a recycle-bin receipt is uncertain. Repeated snapshots with the same page identity remain accessible, as the recycle-bin-repair corpus cold-read demonstrates. Retry coverage now checks both the original snapshot and the latest source edit without deleting earlier copies.
Fixes #119
Assisted-by: gpt-6.1-sol2 files changed, 10 insertions(+), 15 deletions(-)
crates/notebook/src/session.rs-11| ... | @@ -1181,18 +1181,7 @@ impl Notebook { | ... | @@ -1181,18 +1181,7 @@ impl Notebook { |
| 1181 | let transaction = { | 1181 | let transaction = { |
| 1182 | let arena = onestore::Arena::default(); | 1182 | let arena = onestore::Arena::default(); |
| 1183 | let mut section = onestore::Section::open(&arena, bytes)?; | 1183 | let mut section = onestore::Section::open(&arena, bytes)?; |
| 1184 | let mut replaced = Vec::new(); | ||
| 1185 | for (space, ..) in section.pages()? { | ||
| 1186 | if section.page(space)?.identity.is_some_and(|identity| { | ||
| 1187 | pages.iter().any(|page| page.identity == Some(identity)) | ||
| 1188 | }) { | ||
| 1189 | replaced.push(space); | ||
| 1190 | } | ||
| 1191 | } | ||
| 1192 | let mut ops = Vec::new(); | 1184 | let mut ops = Vec::new(); |
| 1193 | if !replaced.is_empty() { | ||
| 1194 | ops.push(Op::Section(SectionOp::Delete(replaced))); | ||
| 1195 | } | ||
| 1196 | for page in pages { | 1185 | for page in pages { |
| 1197 | ops.push(moved(page, author)?); | 1186 | ops.push(moved(page, author)?); |
| 1198 | } | 1187 | } |
crates/notebook/src/session/tests.rs+10-4| ... | @@ -375,10 +375,16 @@ fn recycling_rejects_unconfirmed_appends_and_can_retry_each_stage() { | ... | @@ -375,10 +375,16 @@ fn recycling_rejects_unconfirmed_appends_and_can_retry_each_stage() { |
| 375 | .recycle_pages(std::slice::from_ref(&page), "Fixture") | 375 | .recycle_pages(std::slice::from_ref(&page), "Fixture") |
| 376 | .unwrap(); | 376 | .unwrap(); |
| 377 | let binned = stored_pages(&fs::read(folder.join(&deleted)).unwrap()).unwrap(); | 377 | let binned = stored_pages(&fs::read(folder.join(&deleted)).unwrap()).unwrap(); |
| 378 | assert_eq!(binned.len(), 1, "{rejected}"); | 378 | assert_eq!(binned.len(), 1 + usize::from(retained), "{rejected}"); |
| 379 | assert_eq!(binned[0].page.title, page.title); | 379 | for snapshot in &binned { |
| 380 | assert_eq!(binned[0].page.identity, page.identity); | 380 | assert_eq!(snapshot.page.title, page.title); |
| 381 | assert_eq!(binned[0].page.color, page.color); | 381 | assert_eq!(snapshot.page.identity, page.identity); |
| 382 | } | ||
| 383 | assert_eq!(binned.last().unwrap().page.color, page.color); | ||
| 384 | if retained { | ||
| 385 | assert_eq!(binned[0].page.color, None); | ||
| 386 | assert_eq!(binned.last().unwrap().page.color, Some(0xabcdef)); | ||
| 387 | } | ||
| 382 | assert_eq!(fs::read(folder.join(&path)).unwrap(), source); | 388 | assert_eq!(fs::read(folder.join(&path)).unwrap(), source); |
| 383 | } | 389 | } |
| 384 | } | 390 | } |