feat(history): mode-tagged history + top-of-chain journaling (#30)
Record the submission mode per history entry so advanced commands are reusable in simple mode, and fix the bug where a ':'-one-shot command lost its ':' across sessions (ADR-0052, closing #30). Format: the history.log status token gains an optional ':adv' suffix (ok / ok:adv / err / err:adv); 'source' stays last and canonical, so replay is unaffected. The in-memory ring (still Vec<String>) stores advanced entries ': '-prefixed; recall strips the ':' in advanced mode and keeps it in simple; hydration reconstructs the prefix from the tag. Journaling moved from the worker to the dispatch layer (spawn_dsl_- dispatch / run_replay / app-command sites), where the mode is in scope with no worker plumbing; finalize_persistence writes only yaml/csv (commit-db-last still atomic for state). The journal write is now best-effort (command already committed), consistent with the failure path. App commands journal simple, so they recall bare. Journaling is now uniform (every successful command, per ADR-0034) — closing a gap where show tables/relationships/explain didn't journal. Amends ADR-0034 (status tag + journaling location), ADR-0015 §6 (history.log out of the worker tx), ADR-0040 (journal-write best-effort). 15 worker-level journaling tests retired, re-covered at the new layer (history.rs format, app.rs recall matrix, iteration6 cross-session regression, replay). 2471 pass / 0 fail / 0 skip, clippy clean.
This commit is contained in:
+32
-9
@@ -395,11 +395,26 @@ impl Persistence {
|
||||
}
|
||||
}
|
||||
|
||||
/// Append one successful-command record to `history.log`.
|
||||
pub fn append_history(&self, command_text: &str) -> Result<(), PersistenceError> {
|
||||
/// Append one successful-command record to `history.log`. `advanced`
|
||||
/// (ADR-0052) tags the record `ok:adv` when the command was submitted
|
||||
/// in an advanced effective mode, so hydration can reconstruct its
|
||||
/// `:`-prefixed form for reuse in simple mode.
|
||||
pub fn append_history(
|
||||
&self,
|
||||
command_text: &str,
|
||||
advanced: bool,
|
||||
) -> Result<(), PersistenceError> {
|
||||
let path = self.project_path.join(HISTORY_LOG);
|
||||
let line = history::format_record(command_text, history::utc_iso8601_now());
|
||||
debug!(len = command_text.len(), "persist: append ok record to history.log");
|
||||
let status = history::status_token(history::STATUS_OK, advanced);
|
||||
let line = history::format_record_with_status(
|
||||
command_text,
|
||||
history::utc_iso8601_now(),
|
||||
&status,
|
||||
);
|
||||
debug!(
|
||||
len = command_text.len(),
|
||||
advanced, "persist: append ok record to history.log"
|
||||
);
|
||||
history::append(&path, &line)
|
||||
}
|
||||
|
||||
@@ -410,14 +425,22 @@ impl Persistence {
|
||||
/// transactional `ok` journal). Best-effort at the call site:
|
||||
/// a failure to record a failure must never escalate a user
|
||||
/// error into a fatal (ADR-0034 §4).
|
||||
pub fn append_history_failure(&self, command_text: &str) -> Result<(), PersistenceError> {
|
||||
pub fn append_history_failure(
|
||||
&self,
|
||||
command_text: &str,
|
||||
advanced: bool,
|
||||
) -> Result<(), PersistenceError> {
|
||||
let path = self.project_path.join(HISTORY_LOG);
|
||||
let status = history::status_token(history::STATUS_ERR, advanced);
|
||||
let line = history::format_record_with_status(
|
||||
command_text,
|
||||
history::utc_iso8601_now(),
|
||||
history::STATUS_ERR,
|
||||
&status,
|
||||
);
|
||||
debug!(
|
||||
len = command_text.len(),
|
||||
advanced, "persist: append err record to history.log"
|
||||
);
|
||||
debug!(len = command_text.len(), "persist: append err record to history.log");
|
||||
history::append(&path, &line)
|
||||
}
|
||||
|
||||
@@ -577,8 +600,8 @@ mod tests {
|
||||
fn append_history_creates_and_appends() {
|
||||
let dir = tempdir();
|
||||
let p = Persistence::new(dir.path().to_path_buf());
|
||||
p.append_history("create table Foo with pk id(serial)").unwrap();
|
||||
p.append_history("insert into Foo (1)").unwrap();
|
||||
p.append_history("create table Foo with pk id(serial)", false).unwrap();
|
||||
p.append_history("insert into Foo (1)", false).unwrap();
|
||||
let body = fs::read_to_string(dir.path().join(HISTORY_LOG)).unwrap();
|
||||
let lines: Vec<&str> = body.trim_end().lines().collect();
|
||||
assert_eq!(lines.len(), 2);
|
||||
|
||||
Reference in New Issue
Block a user