review: an undo concludes again only what it had deleted
Undoing a consolidate concluded its moved entries a second time, and a later removal deleted only the newer conclusion. An undo's added entry is now concluded only when the ledger decided a Conclude for it and then an Unconclude: an entry still concluded, or never concluded (a secret session's, one from before sync), gets nothing. Ledger::concluded and unconcluded answer from the decisions, in a module of their own to keep ledger.rs under 500 lines. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
//! What the ledger has decided about one conclusion (M5c spec, section 4): whether it is made, or
|
||||
//! was made and then deleted, by the `Conclude` and `Unconclude` decisions alone, sent or not.
|
||||
//! The owner's undo asks this, so that it concludes again only what it had deleted.
|
||||
|
||||
use crate::honcho::ledger::{Action, Ledger, Workspace};
|
||||
|
||||
impl Ledger {
|
||||
/// Whether the latest decided `Conclude` or `Unconclude` of `text` about `peer` in
|
||||
/// `workspace`, in the ledger's order, is a `Conclude`: its conclusion is made, or will be.
|
||||
pub fn concluded(&self, workspace: Workspace, peer: &str, text: &str) -> bool {
|
||||
self.last_of(workspace, peer, text) == Some(true)
|
||||
}
|
||||
|
||||
/// Whether a `Conclude` of the same was decided, and the latest was followed by an
|
||||
/// `Unconclude`: its conclusion was made, then deleted.
|
||||
pub fn unconcluded(&self, workspace: Workspace, peer: &str, text: &str) -> bool {
|
||||
self.last_of(workspace, peer, text) == Some(false)
|
||||
}
|
||||
|
||||
/// The latest of `Conclude` (true) and, after a `Conclude`, `Unconclude` (false) for the key;
|
||||
/// `None` when no `Conclude` was ever decided.
|
||||
fn last_of(&self, workspace: Workspace, peer: &str, text: &str) -> Option<bool> {
|
||||
let key = |w: &Workspace, p: &str, t: &str| *w == workspace && p == peer && t == text;
|
||||
self.decisions()
|
||||
.fold(None, |last, (_, action)| match action {
|
||||
Action::Conclude {
|
||||
workspace: w,
|
||||
peer: p,
|
||||
text: t,
|
||||
..
|
||||
} if key(w, p, t) => Some(true),
|
||||
Action::Unconclude {
|
||||
workspace: w,
|
||||
peer: p,
|
||||
text: t,
|
||||
} if key(w, p, t) => last.map(|_| false),
|
||||
_ => last,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -185,6 +185,22 @@ pub fn actions(
|
||||
kept
|
||||
}
|
||||
|
||||
/// Whether an undo's `action` is kept: an entry it brings back is concluded again only when its
|
||||
/// conclusion was made and then deleted (M5c spec, section 4: "any it had deleted, written
|
||||
/// again"). One never concluded (a secret session's, from before sync, skipped) or still
|
||||
/// concluded (moved out by `consolidate`) gets nothing. Every other action is kept.
|
||||
fn brought_back(ledger: &Ledger, action: &Action) -> bool {
|
||||
match action {
|
||||
Action::Conclude {
|
||||
workspace,
|
||||
peer,
|
||||
text,
|
||||
..
|
||||
} => ledger.unconcluded(*workspace, peer, text),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// With `[honcho]`: decides each journalled edit into the ledger.
|
||||
pub struct Mirror {
|
||||
ledger: Arc<Mutex<Ledger>>,
|
||||
@@ -207,8 +223,9 @@ impl Mirror {
|
||||
}
|
||||
|
||||
/// Decide the journalled edit `id` (the latest when `None`), called under the index lock
|
||||
/// right after it was journalled, so the ledger has the journal's order. Its parts are
|
||||
/// `Edit { id, part }` from 0. An edit already decided, or asking nothing, adds no line. A
|
||||
/// right after it was journalled, so the ledger has the journal's order; the ledger's lock is
|
||||
/// taken inside the index lock, and before an undo is decided against it. Its parts are
|
||||
/// `Edit { id, part }` from 0, numbering what is decided. An edit already decided, or asking nothing, adds no line. A
|
||||
/// failure is logged; the edit itself stands.
|
||||
pub fn journalled(&self, store: &Store, id: Option<&str>, now: Timestamp, log: &dyn Fn(&str)) {
|
||||
let records = match journal::records(store) {
|
||||
@@ -229,8 +246,11 @@ impl Mirror {
|
||||
return;
|
||||
};
|
||||
let session = session_of(record, &records);
|
||||
let actions = actions(record, session.as_ref(), &self.agent, &self.owner);
|
||||
let mut book = self.ledger.lock().unwrap_or_else(|p| p.into_inner());
|
||||
let mut actions = actions(record, session.as_ref(), &self.agent, &self.owner);
|
||||
if record.undoes.is_some() {
|
||||
actions.retain(|a| brought_back(&book, a));
|
||||
}
|
||||
for (part, action) in actions.into_iter().enumerate() {
|
||||
let Ok(part) = u32::try_from(part) else {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Honcho, the memory this agent shares with the fleet, reached through `roncho` (M5c spec).
|
||||
|
||||
pub mod client;
|
||||
pub mod concluded;
|
||||
pub mod config;
|
||||
pub mod decide;
|
||||
pub mod edits;
|
||||
|
||||
Reference in New Issue
Block a user