host: preserve journals, full traps and embedded agent output

Write new journal entries under logs/core and merge read-only legacy
history without moving SQLite/WAL files. Atomically spool failed batches,
retaining unspoolable entries for event-driven retries. Journal full trap
diagnostics before UTF-8-safe status display. Port session overflow archives
and followable line/byte excerpts to the still-shipped embedded agent.
Document retention/recovery and cover the contracts with regressions.
Include one rustfmt-only normalization in the existing SDK WASI test.

Card: SAU-143
This commit is contained in:
SAU-143 implementer
2026-10-26 13:40:15 +00:00
parent 168795b408
commit 037377fd27
13 changed files with 818 additions and 83 deletions
+5 -5
View File
@@ -36,7 +36,7 @@ async fn status(child: &mut Child) -> std::process::ExitStatus {
}
async fn journal_exists(world: &Path) {
tokio::time::timeout(Duration::from_secs(15), async {
while !world.join("state/core/journal.sqlite").exists() {
while !world.join("logs/core/journal.sqlite").exists() {
tokio::task::yield_now().await;
}
})
@@ -251,7 +251,7 @@ async fn signals_work_during_boot() {
tokio::time::timeout(Duration::from_secs(15), async {
loop {
let db =
rusqlite::Connection::open(world.join("state/core/journal.sqlite")).unwrap();
rusqlite::Connection::open(world.join("logs/core/journal.sqlite")).unwrap();
if let Ok(2) = db.query_row(
"SELECT count(*) FROM journal WHERE line='service start core.lock'",
[],
@@ -336,7 +336,7 @@ async fn console_error_stops_host() {
.await
.unwrap();
assert_eq!(status(&mut child).await.code(), Some(1));
let db = rusqlite::Connection::open(world.join("state/core/journal.sqlite")).unwrap();
let db = rusqlite::Connection::open(world.join("logs/core/journal.sqlite")).unwrap();
let stopped: i64 = db
.query_row(
"SELECT count(*) FROM journal WHERE plugin='probe' AND line='stop'",
@@ -363,9 +363,9 @@ async fn interrupt_leaves_call_running() {
input.write_all(b"probe.busy\n").await.unwrap();
let pid = tokio::time::timeout(Duration::from_secs(20), async {
loop {
if world.join("state/core/journal.sqlite").exists() {
if world.join("logs/core/journal.sqlite").exists() {
let db =
rusqlite::Connection::open(world.join("state/core/journal.sqlite")).unwrap();
rusqlite::Connection::open(world.join("logs/core/journal.sqlite")).unwrap();
if let Ok(pid) = db.query_row(
"SELECT pid FROM journal WHERE plugin='probe' AND line='start busy {}'",
[],