From 1eec999f3828f4444e8da6866e3f67d65f84a388 Mon Sep 17 00:00:00 2001 From: Sander Striker Date: Sat, 31 Oct 2026 13:43:11 +0100 Subject: [PATCH 1/5] refactor: start every message of the binary with amem: The binary is amem, but 74 messages started with memory: and 10 with amem:. Now all 84 start with amem:. The demo filters the lines of amem work by this prefix, so the three demo scripts change too. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Bhj4Ck4y5iwZUsjpgQx8A2 --- crates/memory/src/eventlog.rs | 2 +- crates/memory/src/gofannon.rs | 10 +++++----- crates/memory/src/image.rs | 4 ++-- crates/memory/src/main.rs | 26 +++++++++++++------------- crates/memory/src/mine.rs | 2 +- crates/memory/src/reenact.rs | 6 +++--- crates/memory/src/sources.rs | 2 +- crates/memory/src/stops.rs | 2 +- crates/memory/src/taps.rs | 6 +++--- crates/memory/src/transcripts.rs | 16 ++++++++-------- crates/memory/src/work.rs | 28 ++++++++++++++-------------- crates/memory/src/wslc.rs | 4 ++-- crates/memory/src/wslc_api.rs | 16 ++++++++-------- crates/sandbox/src/lib.rs | 4 ++-- crates/sandbox/src/linux.rs | 6 +++--- crates/sandbox/src/measure.rs | 2 +- crates/server/src/mcp.rs | 2 +- crates/server/src/projection.rs | 8 ++++---- crates/server/src/tape.rs | 2 +- crates/web/src/lib.rs | 2 +- scripts/demo/2-curation.sh | 2 +- scripts/demo/4-fabric.sh | 6 +++--- scripts/demo/7-platform.sh | 2 +- 23 files changed, 80 insertions(+), 80 deletions(-) diff --git a/crates/memory/src/eventlog.rs b/crates/memory/src/eventlog.rs index 87aca355..c6459af6 100644 --- a/crates/memory/src/eventlog.rs +++ b/crates/memory/src/eventlog.rs @@ -39,7 +39,7 @@ pub async fn cmd(m: &Memory, op: LogOp) -> Fallible { LogOp::Materialize { domain } => { let done = m.materialize(domain.as_deref()).await?; for id in &done.behind { - eprintln!("memory: {id} is not at the version the log names"); + eprintln!("amem: {id} is not at the version the log names"); } crate::json(&done) } diff --git a/crates/memory/src/gofannon.rs b/crates/memory/src/gofannon.rs index 67befe85..a0d2505c 100644 --- a/crates/memory/src/gofannon.rs +++ b/crates/memory/src/gofannon.rs @@ -102,7 +102,7 @@ pub async fn cmd(root: &Path, op: GofannonOp) -> Fallible { poll: Duration::from_secs(poll_seconds.max(1)), }; let done = work(&m, &plan).await?; - eprintln!("memory: gofannon worked {done} tasks"); + eprintln!("amem: gofannon worked {done} tasks"); Ok(()) } } @@ -129,7 +129,7 @@ pub async fn work(m: &Arc, plan: &Plan) -> Result, id: String, lease: i64) -> tokio::task: loop { tick.tick().await; if let Err(e) = client.heartbeat(&id, lease).await { - eprintln!("memory: heartbeat on {id}: {e}"); + eprintln!("amem: heartbeat on {id}: {e}"); return; } } @@ -235,10 +235,10 @@ async fn settle( .await?; if done { client.complete(&task.id, &handoff).await?; - eprintln!("memory: {} completed, handoff {handoff}", task.id); + eprintln!("amem: {} completed, handoff {handoff}", task.id); } else { client.release(&task.id, Some(&handoff)).await?; - eprintln!("memory: {} released, handoff {handoff}", task.id); + eprintln!("amem: {} released, handoff {handoff}", task.id); } Ok(()) } diff --git a/crates/memory/src/image.rs b/crates/memory/src/image.rs index 108e96bd..4e7ea446 100644 --- a/crates/memory/src/image.rs +++ b/crates/memory/src/image.rs @@ -70,7 +70,7 @@ pub fn unpack(root: &Path, image: &str) -> Fallible { std::fs::remove_dir_all(&fresh)?; } std::fs::create_dir_all(&fresh)?; - eprintln!("memory: exporting {image} from {rt}"); + eprintln!("amem: exporting {image} from {rt}"); let id = run(rt, &["create", image, "true"])?; let id = id.lines().last().unwrap_or_default().trim().to_string(); let result = (|| -> Fallible<()> { @@ -99,7 +99,7 @@ pub fn unpack(root: &Path, image: &str) -> Fallible { } std::fs::rename(&fresh, &rootfs)?; std::fs::write(rootfs.with_extension("source"), format!("{image}\n"))?; - eprintln!("memory: unpacked into {}", rootfs.display()); + eprintln!("amem: unpacked into {}", rootfs.display()); Ok(rootfs) } diff --git a/crates/memory/src/main.rs b/crates/memory/src/main.rs index 0796de3e..d70995f0 100644 --- a/crates/memory/src/main.rs +++ b/crates/memory/src/main.rs @@ -1748,7 +1748,7 @@ fn route_for( )?; if var == "GH_TOKEN" { eprintln!( - "memory: copilot holds your GitHub login's token, which reaches every \ + "amem: copilot holds your GitHub login's token, which reaches every \ repository the login can; a token with only the Copilot Requests \ permission, as COPILOT_GITHUB_TOKEN, keeps that out of the sandbox" ); @@ -2021,12 +2021,12 @@ fn record_reported_usage(p: &Prepared) { .telemetry() .record_reported(p.memory.session_id(), &p.provider, usage) { - eprintln!("memory: could not record reported usage: {e}"); + eprintln!("amem: could not record reported usage: {e}"); } } if let Some((pct, window)) = reported.plan_used_percent { eprintln!( - "memory: the harness reports {pct:.1}% of its plan's {}-hour window used", + "amem: the harness reports {pct:.1}% of its plan's {}-hour window used", window / 60 ); } @@ -2079,7 +2079,7 @@ fn report_usage(egress: &Egress) { if rows.is_empty() { return; } - eprintln!("memory: usage this root, by destination and model:"); + eprintln!("amem: usage this root, by destination and model:"); for r in rows { eprintln!( " {:<10} {:<26} {:<8} calls {:>4} in {:>8} out {:>8} cache {:>8}", @@ -2186,14 +2186,14 @@ fn live_mount(p: &Prepared, harness: Harness) -> Option { match dm_mount::mount(p.memory.clone(), &p.projection, &at) { Ok(m) => { eprintln!( - "memory: the projection at {} is a live mount: every open of an entry is a get", + "amem: the projection at {} is a live mount: every open of an entry is a get", dm_sandbox::INSIDE_PROJECTION ); Some(m) } Err(e) => { eprintln!( - "memory: the projection at {} is a render: {e}", + "amem: the projection at {} is a render: {e}", dm_sandbox::INSIDE_PROJECTION ); None @@ -2405,7 +2405,7 @@ async fn golden_suite( .ok_or_else(|| { format!("the platform holds no verified eval artifact named {name}") })?; - eprintln!("memory: the suite is the platform's {}", a.entry); + eprintln!("amem: the suite is the platform's {}", a.entry); golden::Suite::parse(&a.text) } (None, None) => Err("name a suite, or --platform".into()), @@ -3228,7 +3228,7 @@ fn empty_record(root: &Path) -> Result> { )); std::fs::create_dir_all(&dir)?; Memory::init(&dir, &grants.owner, &domain)?; - eprintln!("memory: empty memory at {}", dir.display()); + eprintln!("amem: empty memory at {}", dir.display()); Ok(dir) } @@ -3406,7 +3406,7 @@ fn announce(runner: &Runner, p: &Prepared, harness: Harness, workdir: &Path) { _ => workdir.to_path_buf(), }; eprintln!( - "memory: {} {how} {} · model calls via {} at ceiling {} · session {}", + "amem: {} {how} {} · model calls via {} at ceiling {} · session {}", harness.binary(), shown.display(), p.ceiling_of, @@ -3449,7 +3449,7 @@ async fn platform_model(memory: &Memory, harness: Harness) -> Option { .flatten()?; let v: serde_json::Value = serde_json::from_str(&a.text).ok()?; let model = v.get("model")?.as_str()?.to_string(); - eprintln!("memory: model {model} from the platform's {}", a.entry); + eprintln!("amem: model {model} from the platform's {}", a.entry); Some(model) } @@ -3666,7 +3666,7 @@ impl Session { via: MineVia, ) -> Result, Box> { let Some(t) = mine::newest_transcript(&self.p.home) else { - eprintln!("memory: nothing to mine; no transcript under the private home"); + eprintln!("amem: nothing to mine; no transcript under the private home"); return Ok(Vec::new()); }; let model = model::resolve(&self.p.egress, &self.p.server.provider, model).await; @@ -3688,7 +3688,7 @@ impl Session { ) .await? }; - eprintln!("memory: mined {} entries from {}", ids.len(), t.display()); + eprintln!("amem: mined {} entries from {}", ids.len(), t.display()); client.close().await.ok(); Ok(ids) } @@ -3810,7 +3810,7 @@ impl Session { at: String::new(), }; if let Err(e) = self.p.egress.telemetry().record_run(&run) { - eprintln!("memory: the run's resources were not kept: {e}"); + eprintln!("amem: the run's resources were not kept: {e}"); } Ok((code, out)) } diff --git a/crates/memory/src/mine.rs b/crates/memory/src/mine.rs index 77aa5029..24513d94 100644 --- a/crates/memory/src/mine.rs +++ b/crates/memory/src/mine.rs @@ -117,7 +117,7 @@ pub async fn write_proposals( domain: None, }) .await?; - eprintln!("memory: mined {} {id}: {}", p.kind, p.title); + eprintln!("amem: mined {} {id}: {}", p.kind, p.title); ids.push(id); } Ok(ids) diff --git a/crates/memory/src/reenact.rs b/crates/memory/src/reenact.rs index ded84b2f..3457eca7 100644 --- a/crates/memory/src/reenact.rs +++ b/crates/memory/src/reenact.rs @@ -323,7 +323,7 @@ fn checkout(repo: &Path, commit: &str, run: &str) -> Fallibly { fn remove_checkout(into: &Path) { if std::fs::remove_dir_all(into).is_err() { - eprintln!("memory: the checkout at {} was left", into.display()); + eprintln!("amem: the checkout at {} was left", into.display()); } } @@ -498,7 +498,7 @@ async fn run_once( session.memory().set_playback(play.clone()); session.memory().disable_read_log(); eprintln!( - "memory: re-enacting {} ({} calls on its tape) as {}", + "amem: re-enacting {} ({} calls on its tape) as {}", args.session, play.played().tape_calls, session.memory().session_id() @@ -540,7 +540,7 @@ fn tree_for( if let Some(c) = commit { return Ok((checkout(repo, c, &format!("{session}-{run}"))?, None)); } - eprintln!("memory: {session} recorded no commit; the re-run works in an empty directory"); + eprintln!("amem: {session} recorded no commit; the re-run works in an empty directory"); // as an empty record is made for an evaluation's baseline let d = std::env::temp_dir().join(format!("amem-reenact-{}-{run}", std::process::id())); std::fs::create_dir_all(&d)?; diff --git a/crates/memory/src/sources.rs b/crates/memory/src/sources.rs index 9044f768..7e0f84b4 100644 --- a/crates/memory/src/sources.rs +++ b/crates/memory/src/sources.rs @@ -77,7 +77,7 @@ pub async fn cmd(m: &Memory, op: SourceOp) -> Fallible { let id = id.strip_prefix(dm_server::sources::CITATION).unwrap_or(&id); let s = m.release_source(id).await?; eprintln!( - "memory: {} released; it carries {}", + "amem: {} released; it carries {}", s.id, if s.findings.is_empty() { "nothing the scan found".to_string() diff --git a/crates/memory/src/stops.rs b/crates/memory/src/stops.rs index 9c7752de..e6d1da73 100644 --- a/crates/memory/src/stops.rs +++ b/crates/memory/src/stops.rs @@ -194,7 +194,7 @@ fn say(signal: i32) -> bool { 2 => "SIGINT", _ => "SIGTERM", }; - let line = format!("memory: {name}: ending the run and cleaning up\n"); + let line = format!("amem: {name}: ending the run and cleaning up\n"); std::io::stderr().write_all(line.as_bytes()).is_ok() } diff --git a/crates/memory/src/taps.rs b/crates/memory/src/taps.rs index 2c51d209..42371f9d 100644 --- a/crates/memory/src/taps.rs +++ b/crates/memory/src/taps.rs @@ -74,7 +74,7 @@ pub async fn run( .and_then(|var| crate::present(std::env::var(var).ok())); if grant.credential.is_some() && credential.is_none() { eprintln!( - "memory: {} is not set; the tap runs without a credential", + "amem: {} is not set; the tap runs without a credential", grant.credential.as_deref().unwrap_or_default() ); } @@ -94,12 +94,12 @@ pub async fn run( (Ok(outcome), _) => println!("{}", serde_json::to_string_pretty(&outcome)?), (Err(e), None) => return Err(e.into()), // on a schedule, one failed pull is reported and the next one still comes - (Err(e), Some(_)) => eprintln!("memory: tap {name}: {e}"), + (Err(e), Some(_)) => eprintln!("amem: tap {name}: {e}"), } let Some(secs) = every else { return Ok(()); }; - eprintln!("memory: tap {name} runs again in {secs}s"); + eprintln!("amem: tap {name} runs again in {secs}s"); tokio::time::sleep(std::time::Duration::from_secs(secs.max(1))).await; } } diff --git a/crates/memory/src/transcripts.rs b/crates/memory/src/transcripts.rs index 693aa64d..fd218e0f 100644 --- a/crates/memory/src/transcripts.rs +++ b/crates/memory/src/transcripts.rs @@ -75,21 +75,21 @@ pub async fn sweep(m: &Memory) -> Result, Box> let swept = m.sweep_transcripts(now).await?; // decision contexts run on the same clock, and go whole: no entry cites them for session in m.sweep_contexts(now).await? { - eprintln!("memory: decision contexts of {session} expired and were dropped"); + eprintln!("amem: decision contexts of {session} expired and were dropped"); } // and the tapes a re-run is answered from, unless pinned for a benchmark for session in m.sweep_tapes(now).await? { // and the reports of its re-runs, which quote what the runs wrote and said crate::reenact::forget_runs(m.root(), &session); - eprintln!("memory: the tape of {session} expired and was dropped, with its re-runs"); + eprintln!("amem: the tape of {session} expired and was dropped, with its re-runs"); } // and so do the sources tools brought in, except what a live entry cites for id in m.sweep_sources(now).await? { - eprintln!("memory: source {id} expired, uncited, and was dropped"); + eprintln!("amem: source {id} expired, uncited, and was dropped"); } for s in &swept { eprintln!( - "memory: transcript {} expired: {} turns kept as {} excerpts, {} dropped", + "amem: transcript {} expired: {} turns kept as {} excerpts, {} dropped", s.session, s.kept.len(), s.excerpts, @@ -147,7 +147,7 @@ pub async fn keep_newest( match keep_file(memory, harness, domain, Some(home), &path).await { Ok(k) => { eprintln!( - "memory: transcript kept as source {} in {}: {} turns, {}, until {}", + "amem: transcript kept as source {} in {}: {} turns, {}, until {}", k.session, k.domain, k.turns, @@ -158,7 +158,7 @@ pub async fn keep_newest( } Err(e) => { eprintln!( - "memory: the transcript at {} was not kept: {e}", + "amem: the transcript at {} was not kept: {e}", path.display() ); None @@ -175,7 +175,7 @@ pub async fn remove_kept(memory: &Memory, home: &Path) -> Vec o, Err(e) => { - eprintln!("memory: the harness's transcripts were left in its home: {e}"); + eprintln!("amem: the harness's transcripts were left in its home: {e}"); return Vec::new(); } }; @@ -188,7 +188,7 @@ pub async fn remove_kept(memory: &Memory, home: &Path) -> Vec) -> Fallible { let (sr, sw) = tokio::io::split(server_io); tokio::spawn(async move { if let Err(e) = mcp::serve_launcher_pipe(memory, sr, sw).await { - eprintln!("memory: in-process server: {e}"); + eprintln!("amem: in-process server: {e}"); } }); let (cr, cw) = tokio::io::split(client_io); @@ -119,7 +119,7 @@ pub async fn file_outbox( }) .await?; eprintln!( - "memory: handoff {id} from the harness's hook ({})", + "amem: handoff {id} from the harness's hook ({})", note.event.suffix() ); std::fs::remove_file(¬e.path).ok(); @@ -193,13 +193,13 @@ pub async fn prompted( let new: Vec<&String> = after.difference(&before).collect(); if new.is_empty() && !no_handoff { eprintln!( - "memory: the run left no handoff; the next session starts from nothing (pass --no-handoff if that is intended)" + "amem: the run left no handoff; the next session starts from nothing (pass --no-handoff if that is intended)" ); client.close().await.ok(); return Ok(if code == 0 { STOPPED } else { code }); } for id in new { - eprintln!("memory: handoff {id}"); + eprintln!("amem: handoff {id}"); } client.close().await.ok(); Ok(code) @@ -275,7 +275,7 @@ pub async fn run(session: &Session, options: &Options) -> Fallible { let Some(task) = claimed else { drop(in_flight); if !options.keep_going { - eprintln!("memory: nothing claimable"); + eprintln!("amem: nothing claimable"); return Ok(if last == NOTHING_TO_DO { NOTHING_TO_DO } else { @@ -306,7 +306,7 @@ pub async fn run(session: &Session, options: &Options) -> Fallible { crate::MineVia::Api }; if let Err(e) = session.mine(plan.model.as_deref(), via).await { - eprintln!("memory: mining failed: {e}"); + eprintln!("amem: mining failed: {e}"); } } if !options.keep_going { @@ -322,7 +322,7 @@ async fn one( options: &Options, ) -> Fallible { let lease_seconds = options.lease_seconds; - eprintln!("memory: claimed {}: {}", task.id, task.title); + eprintln!("amem: claimed {}: {}", task.id, task.title); let holding = Holding::of(&task.id); let memory = session.memory(); let platform = Platform::for_harness(&memory, session.harness()).await; @@ -346,7 +346,7 @@ async fn one( loop { tick.tick().await; if let Err(e) = client.heartbeat(&id, lease_seconds).await { - eprintln!("memory: heartbeat on {id}: {e}"); + eprintln!("amem: heartbeat on {id}: {e}"); return; } } @@ -430,7 +430,7 @@ async fn settle( match now.status.as_str() { "completed" => { eprintln!( - "memory: {} completed, handoff {}", + "amem: {} completed, handoff {}", task.id, now.handoff.as_deref().unwrap_or("-") ); @@ -452,7 +452,7 @@ async fn settle( .await?; client.complete(&task.id, &handoff).await?; eprintln!( - "memory: {} completed with its report as handoff {handoff}", + "amem: {} completed with its report as handoff {handoff}", task.id ); Ok(0) @@ -476,13 +476,13 @@ async fn settle( .await?; client.release(&task.id, Some(&handoff)).await?; eprintln!( - "memory: {} released; its output is filed as handoff {handoff}", + "amem: {} released; its output is filed as handoff {handoff}", task.id ); Ok(STOPPED) } other => { - eprintln!("memory: {} is now {other}", task.id); + eprintln!("amem: {} is now {other}", task.id); Ok(if code == 0 { STOPPED } else { code }) } } @@ -643,7 +643,7 @@ async fn prefetched(memory: &Memory, task: &Task) -> String { match memory.prefetch(&query, &prefetch::Plan::default()).await { Ok(found) => { eprintln!( - "memory: prefetched {} summaries ({} tokens): {}", + "amem: prefetched {} summaries ({} tokens): {}", found.hits.len(), found.tokens, found.ids().join(", ") @@ -651,7 +651,7 @@ async fn prefetched(memory: &Memory, task: &Task) -> String { prefetch_section(&found) } Err(e) => { - eprintln!("memory: no prefetch for {}: {e}", task.id); + eprintln!("amem: no prefetch for {}: {e}", task.id); String::new() } } diff --git a/crates/memory/src/wslc.rs b/crates/memory/src/wslc.rs index 723000e0..253663f1 100644 --- a/crates/memory/src/wslc.rs +++ b/crates/memory/src/wslc.rs @@ -469,7 +469,7 @@ fn run_api(l: &Launch) -> Fallible { match ready { Ok((api, storage)) => crate::wslc_api::run(l, &api, &storage), Err(why) if l.via == Via::Auto => { - eprintln!("memory: not over the C API ({why}); driving the wslc command line"); + eprintln!("amem: not over the C API ({why}); driving the wslc command line"); run_cli(l) } Err(why) => Err(why.into()), @@ -637,7 +637,7 @@ fn gateway_up(root: &Path) -> Fallible { let probe = "import urllib.request,sys; urllib.request.urlopen('http://127.0.0.1:4000/health/liveliness', timeout=3)"; for _ in 0..60 { if run_ok(&s(&["exec", GATEWAY_LITELLM, "python3", "-c", probe])).is_ok() { - eprintln!("memory: gateway up inside the VM at http://{GATEWAY_LITELLM}:4000"); + eprintln!("amem: gateway up inside the VM at http://{GATEWAY_LITELLM}:4000"); return Ok(master); } std::thread::sleep(Duration::from_secs(2)); diff --git a/crates/memory/src/wslc_api.rs b/crates/memory/src/wslc_api.rs index 5744d4fb..1fb0d497 100644 --- a/crates/memory/src/wslc_api.rs +++ b/crates/memory/src/wslc_api.rs @@ -357,8 +357,8 @@ mod on_windows { } for v in stale { match session.delete_volume(&v) { - Ok(()) => eprintln!("memory: removed {v}, left by a launch that was killed"), - Err(e) => eprintln!("memory: {v}, left by a launch that was killed, stays: {e}"), + Ok(()) => eprintln!("amem: removed {v}, left by a launch that was killed"), + Err(e) => eprintln!("amem: {v}, left by a launch that was killed, stays: {e}"), } } } @@ -374,7 +374,7 @@ mod on_windows { if process_alive(pid) { return false; } - eprintln!("memory: ending {name}, left by process {pid}, which is gone"); + eprintln!("amem: ending {name}, left by process {pid}, which is gone"); let args = ["--session", name, "system", "session", "terminate"].map(String::from); wslc::run_ok(&args).is_ok() } @@ -403,7 +403,7 @@ mod on_windows { let s = session.clone(); Some(rt.spawn(async move { if tokio::signal::ctrl_c().await.is_ok() { - eprintln!("memory: interrupted; ending the session"); + eprintln!("amem: interrupted; ending the session"); s.terminate().ok(); std::fs::remove_dir_all(&projection).ok(); std::process::exit(130); @@ -429,14 +429,14 @@ mod on_windows { match provision(image, &store, refresh, || cli_image_id(image)) { Provision::Present { id } => { eprintln!( - "memory: {image} {} from this session's store; after a rebuild, \ + "amem: {image} {} from this session's store; after a rebuild, \ `memory wslc-api-check --refresh`", id.get(..12).unwrap_or(&id) ); Ok(()) } Provision::Pull => { - eprintln!("memory: pulling {image} into this session's store"); + eprintln!("amem: pulling {image} into this session's store"); session.pull_image(image, None).map_err(Into::into) } Provision::Load { stale } => { @@ -451,7 +451,7 @@ mod on_windows { /// `wslc save` the image to a file beside the session's disk, load it, and remove the /// file. fn load_from_cli(session: &Session, image: &str, scratch: &Path) -> Fallible<()> { - eprintln!("memory: loading {image} into this session's store; once per image"); + eprintln!("amem: loading {image} into this session's store; once per image"); let archive = scratch.join("image.tar"); let started = std::time::Instant::now(); let status = Command::new(wslc::wslc()) @@ -471,7 +471,7 @@ mod on_windows { format!("{image} was loaded but the session's store does not list it").into(), ); } - eprintln!("memory: loaded in {:.0?}", started.elapsed()); + eprintln!("amem: loaded in {:.0?}", started.elapsed()); Ok(()) } diff --git a/crates/sandbox/src/lib.rs b/crates/sandbox/src/lib.rs index 1497ffce..544fc2f9 100644 --- a/crates/sandbox/src/lib.rs +++ b/crates/sandbox/src/lib.rs @@ -1188,7 +1188,7 @@ url = "{relay}/mcp" if let Ok(bin) = find_on_path("codex") { if !bin.with_file_name("codex-code-mode-host").is_file() { eprintln!( - "memory: warning: {} has no codex-code-mode-host beside it; Codex's tools, memory among them, will fail. Install it from the same Codex release", + "amem: warning: {} has no codex-code-mode-host beside it; Codex's tools, memory among them, will fail. Install it from the same Codex release", bin.display() ); } @@ -1839,7 +1839,7 @@ function note(event, sessionID, extra) { try { hook({ hook_event_name: event, session_id: sessionID, transcript_path: transcript(sessionID), ...extra }); } catch (err) { - console.warn(`memory: ${event} note not left: ${err.message}`); + console.warn(`amem: ${event} note not left: ${err.message}`); } } diff --git a/crates/sandbox/src/linux.rs b/crates/sandbox/src/linux.rs index 0ca89e3e..8cec5c76 100644 --- a/crates/sandbox/src/linux.rs +++ b/crates/sandbox/src/linux.rs @@ -502,7 +502,7 @@ fn command(plan: &Plan) -> Result<(Command, PathBuf), Error> { go().map_err(|e| { // std carries only the raw errno back to the parent, so say what // failed here, where stderr is still the terminal - eprintln!("memory: sandbox: {e}"); + eprintln!("amem: sandbox: {e}"); std::io::Error::other(e.to_string()) })?; cloexec_from_three(open_files) @@ -516,7 +516,7 @@ fn command(plan: &Plan) -> Result<(Command, PathBuf), Error> { /// Say what failed between fork and exec, on stderr, without allocating. fn say(what: &[u8]) { - for part in [b"memory: sandbox: ".as_slice(), what, b"\n"] { + for part in [b"amem: sandbox: ".as_slice(), what, b"\n"] { // SAFETY: a write of a buffer with its own length to stderr. unsafe { libc::write(2, part.as_ptr().cast(), part.len()) }; } @@ -647,7 +647,7 @@ fn say_the_relay_died(signal: i32, core_dumped: bool) { } let number = &digits[first..]; let mut buf = [0u8; 96]; - let mut n = put(&mut buf, 0, b"memory: the relay was killed by "); + let mut n = put(&mut buf, 0, b"amem: the relay was killed by "); if let Some(name) = crate::measure::signal_name(signal) { n = put(&mut buf, n, name.as_bytes()); n = put(&mut buf, n, b" (signal "); diff --git a/crates/sandbox/src/measure.rs b/crates/sandbox/src/measure.rs index e026814f..dbb5c7a6 100644 --- a/crates/sandbox/src/measure.rs +++ b/crates/sandbox/src/measure.rs @@ -197,7 +197,7 @@ fn exit_code_as(status: ExitStatus, program: &OsStr, stopped: bool) -> i32 { |name| format!("{name} (signal {signal})"), ); let line = format!( - "memory: {} was killed by {name}{core}\n", + "amem: {} was killed by {name}{core}\n", program.to_string_lossy() ); // one write, so what other threads print does not land inside the line diff --git a/crates/server/src/mcp.rs b/crates/server/src/mcp.rs index 01b1bc42..cfa7822a 100644 --- a/crates/server/src/mcp.rs +++ b/crates/server/src/mcp.rs @@ -935,7 +935,7 @@ impl ServerHandler for McpServer { .tape_call(&tool, &arguments, &value, is_error) .await { - eprintln!("memory: {tool} was not kept on the tape: {e}"); + eprintln!("amem: {tool} was not kept on the tape: {e}"); } result } diff --git a/crates/server/src/projection.rs b/crates/server/src/projection.rs index a8773cc5..cce13243 100644 --- a/crates/server/src/projection.rs +++ b/crates/server/src/projection.rs @@ -138,7 +138,7 @@ impl Memory { if domain == RECALLS { // a domain by that name would sit where the recall pages do eprintln!( - "memory: the domain {RECALLS} is not projected: the name is the recall pages'" + "amem: the domain {RECALLS} is not projected: the name is the recall pages'" ); continue; } @@ -230,7 +230,7 @@ impl Memory { }); match landed { Ok(name) => r.projected = Some(format!("{RECALLS}/{}/{name}", self.session_id)), - Err(e) => eprintln!("memory: projection at {}: {e}", dir.display()), + Err(e) => eprintln!("amem: projection at {}: {e}", dir.display()), } } @@ -274,7 +274,7 @@ impl Memory { pub(crate) async fn refresh_projection(&self) { if let Some(dir) = &self.projection { if let Err(e) = self.render(dir).await { - eprintln!("memory: projection at {}: {e}", dir.display()); + eprintln!("amem: projection at {}: {e}", dir.display()); } } } @@ -370,7 +370,7 @@ impl Memory { pub(crate) async fn refresh_projection_after_erasure(&self) { if let Some(dir) = &self.projection { if let Err(e) = self.sweep_recalls(dir, false) { - eprintln!("memory: projection at {}: {e}", dir.display()); + eprintln!("amem: projection at {}: {e}", dir.display()); } } self.refresh_projection().await; diff --git a/crates/server/src/tape.rs b/crates/server/src/tape.rs index 96aee53e..bbe32422 100644 --- a/crates/server/src/tape.rs +++ b/crates/server/src/tape.rs @@ -505,7 +505,7 @@ impl Memory { ) -> Result, Error> { match self.header_in(domain, session).await { Err(Error::Transcript(e)) => { - eprintln!("memory: the tape of {session} has a header that does not parse, left as it is: {e}"); + eprintln!("amem: the tape of {session} has a header that does not parse, left as it is: {e}"); Ok(None) } other => other, diff --git a/crates/web/src/lib.rs b/crates/web/src/lib.rs index 969e4788..ca7fbaeb 100644 --- a/crates/web/src/lib.rs +++ b/crates/web/src/lib.rs @@ -46,7 +46,7 @@ pub enum Error { #[error("listen: {0}")] Io(#[from] std::io::Error), /// The record. - #[error("memory: {0}")] + #[error("amem: {0}")] Memory(#[from] dm_server::Error), } diff --git a/scripts/demo/2-curation.sh b/scripts/demo/2-curation.sh index d6e0b071..9f7fdd78 100755 --- a/scripts/demo/2-curation.sh +++ b/scripts/demo/2-curation.sh @@ -18,7 +18,7 @@ a task list --domain dom-demo --status admitted \ say "A librarian run" "$WORKER_HARNESS on the gateway's $WORKER_MODEL claims the top curation task and does it. An entry rewritten while holding a librarian's task lands one tier up, curated, and never further on an agent's word." top=$(a task list --domain dom-demo --status admitted | j "next((t['id'] for t in d if (t.get('origin') or '').startswith(('librarian:','checker:'))), '')") if [ -n "$top" ]; then - ( cd "$(mktemp -d)" && a work --harness "$WORKER_HARNESS" --auth gateway --model "$WORKER_MODEL" --backend namespaces --lease-seconds 900 --task "$top" 2>&1 | grep -E '^memory: (claimed|task|prefetched)' ) || true + ( cd "$(mktemp -d)" && a work --harness "$WORKER_HARNESS" --auth gateway --model "$WORKER_MODEL" --backend namespaces --lease-seconds 900 --task "$top" 2>&1 | grep -E '^amem: (claimed|task|prefetched)' ) || true else echo " no curation task is admitted: the cycle filed none, or the domain does not admit its own filings (a record from an older demo; make demo-ready RESET=1)" fi diff --git a/scripts/demo/4-fabric.sh b/scripts/demo/4-fabric.sh index d56c71cf..3a183ff7 100755 --- a/scripts/demo/4-fabric.sh +++ b/scripts/demo/4-fabric.sh @@ -43,7 +43,7 @@ if [ -n "${HARNESS:-}" ]; then say "Subagents on the board" "A $HARNESS session is asked to delegate. Each subagent it would spawn is filed as a task of its own instead, with a continuation that waits for them, so the work survives the session and any worker can do it. The original task goes back on the board but waits: nobody may claim it while its continuation is open." parent=$(a task create "Compare two decisions" --domain dom-demo --priority 20 --body "Use two subagents, one per decision, to summarise DR-19 and DR-22 from the memory record; then combine their answers into a handoff and complete this task." | j "d['id']") a task admit "$parent" >/dev/null - ( cd "$(mktemp -d)" && a work --harness "$HARNESS" --auth "${AUTH:-subscription}" $MODEL_ARG --lease-seconds 900 --task "$parent" 2>&1 | grep -E '^memory: (claimed|task|board|filed)' ) || true + ( cd "$(mktemp -d)" && a work --harness "$HARNESS" --auth "${AUTH:-subscription}" $MODEL_ARG --lease-seconds 900 --task "$parent" 2>&1 | grep -E '^amem: (claimed|task|board|filed)' ) || true tree() { a task tree "$parent" | j "'\n'.join(f\" {c['id']} {(c.get('origin') or '').split(':')[0]:<10} {c['status']:<11} {c['title']}\" for c in d.get('children', []))" a task get "$parent" | j "f\" {d['id']} original {d['status']:<11} {d['title']}\" + (' (waits on its continuation)' if d['status'] == 'admitted' else ' (closed by its continuation, with its handoff)' if d['status'] == 'completed' else '')" @@ -53,13 +53,13 @@ if [ -n "${HARNESS:-}" ]; then if [ -n "$kids" ]; then say "The board runs the subagents' tasks" "$WORKER_HARNESS on the gateway's $WORKER_MODEL takes each subagent task, one at a time, and files its report as the handoff." for k in $kids; do - ( cd "$(mktemp -d)" && a work --harness "$WORKER_HARNESS" --auth gateway --model "$WORKER_MODEL" --backend namespaces --lease-seconds 900 --task "$k" 2>&1 | grep -E '^memory: (claimed|task)' ) || true + ( cd "$(mktemp -d)" && a work --harness "$WORKER_HARNESS" --auth gateway --model "$WORKER_MODEL" --backend namespaces --lease-seconds 900 --task "$k" 2>&1 | grep -E '^amem: (claimed|task)' ) || true done cont=$(a task tree "$parent" | j "next((c['id'] for c in d.get('children', []) if (c.get('origin') or '').startswith('continues:') and c['status']=='admitted'), '')") open=$(a task tree "$parent" | j "' '.join(c['id'] for c in d.get('children', []) if (c.get('origin') or '').startswith('task:') and c['status']!='completed')") if [ -n "$cont" ] && [ -z "$open" ]; then say "Fan-in" "The continuation waited for both; it runs now, with their handoffs in its prompt, and completes with a handoff of its own. Its completion closes the original task it resumed, with the same handoff." - ( cd "$(mktemp -d)" && a work --harness "$HARNESS" --auth "${AUTH:-subscription}" $MODEL_ARG --lease-seconds 900 --task "$cont" 2>&1 | grep -E '^memory: (claimed|task)' ) || true + ( cd "$(mktemp -d)" && a work --harness "$HARNESS" --auth "${AUTH:-subscription}" $MODEL_ARG --lease-seconds 900 --task "$cont" 2>&1 | grep -E '^amem: (claimed|task)' ) || true elif [ -n "$cont" ]; then echo " the continuation $cont still waits for: $open" fi diff --git a/scripts/demo/7-platform.sh b/scripts/demo/7-platform.sh index f725242c..9439696a 100644 --- a/scripts/demo/7-platform.sh +++ b/scripts/demo/7-platform.sh @@ -65,7 +65,7 @@ if gateway; then say "A task under the definition" "A question filed for $WORKER_HARNESS, launched with no model named: the platform's default model is used, and the verified definition is added to the task's prompt." task=$(a task create "What did DR-22 decide about the format memory entries travel in?" --domain dom-demo --priority 30 --body "Answer from the memory record, in two or three sentences, and file the answer as your handoff." | j "d['id']") a task admit "$task" >/dev/null - ( cd "$(mktemp -d)" && a work --harness "$WORKER_HARNESS" --auth gateway --model "$WORKER_MODEL" --backend namespaces --lease-seconds 900 --task "$task" 2>&1 | grep -E '^memory: (claimed|task|.*confined)' ) || true + ( cd "$(mktemp -d)" && a work --harness "$WORKER_HARNESS" --auth gateway --model "$WORKER_MODEL" --backend namespaces --lease-seconds 900 --task "$task" 2>&1 | grep -E '^amem: (claimed|task|.*confined)' ) || true handoff=$(a task get "$task" | j "d.get('handoff') or ''") if [ -n "$handoff" ]; then a get "$handoff" 2>/dev/null | grep -q "Checked against the platform definition" \ From f6ce6e55ceae39e5338a956e2963f260513f247e Mon Sep 17 00:00:00 2001 From: Sander Striker Date: Sat, 31 Oct 2026 14:36:47 +0100 Subject: [PATCH 2/5] fix: answer the adversarial pass on the message prefix The pass found two hook messages that started with "memory hook:", a spike script that still removed "memory: " lines, and an AppArmor comment that showed the old output. Now they use amem:. A new test fails on a message that starts with the old name. The web error for the record was "memory:", which named the record, not the binary. Now it is "record:". Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Bhj4Ck4y5iwZUsjpgQx8A2 --- crates/memory/src/main.rs | 4 +- crates/memory/tests/message_prefix.rs | 51 +++++++++++++++++++++ crates/web/src/lib.rs | 2 +- packaging/apparmor/amem | 2 +- spikes/harness-containers/seatbelt-steps.sh | 2 +- 5 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 crates/memory/tests/message_prefix.rs diff --git a/crates/memory/src/main.rs b/crates/memory/src/main.rs index d70995f0..25f6fcf2 100644 --- a/crates/memory/src/main.rs +++ b/crates/memory/src/main.rs @@ -1282,10 +1282,10 @@ fn main() { match outbox { Some(outbox) => { if let Err(e) = hooks::run(&outbox, harness) { - eprintln!("memory hook: {e}"); + eprintln!("amem: hook: {e}"); } } - None => eprintln!("memory hook: no MEMORY_OUTBOX and no HOME"), + None => eprintln!("amem: hook: no MEMORY_OUTBOX and no HOME"), } std::process::exit(0); } diff --git a/crates/memory/tests/message_prefix.rs b/crates/memory/tests/message_prefix.rs new file mode 100644 index 00000000..20da4706 --- /dev/null +++ b/crates/memory/tests/message_prefix.rs @@ -0,0 +1,51 @@ +//! Every line the binary writes for a person starts with `amem:`, the command's name. +//! The demo selects the lines of `amem work` by that prefix, so a message under the old +//! name is a line the demo drops without a word. This reads the sources, since no run +//! reaches every message. + +use std::path::Path; + +fn sources(dir: &Path, out: &mut Vec) { + for entry in std::fs::read_dir(dir).expect("crates/ reads") { + let path = entry.expect("an entry").path(); + if path.is_dir() { + if path.file_name().is_some_and(|n| n != "target") { + sources(&path, out); + } + } else if path.extension().is_some_and(|e| e == "rs") { + out.push(path); + } + } +} + +#[test] +fn no_message_starts_with_the_old_name() { + let crates = Path::new(env!("CARGO_MANIFEST_DIR")).join(".."); + let mut files = Vec::new(); + sources(&crates, &mut files); + assert!( + files.len() > 50, + "found only {} sources under {}", + files.len(), + crates.display() + ); + // the old spellings, assembled so this file does not hold them + let old: Vec = ["\"", "`", "b\""] + .iter() + .flat_map(|q| [format!("{q}memory: "), format!("{q}memory hook:")]) + .collect(); + let mut found = Vec::new(); + for file in &files { + let text = std::fs::read_to_string(file).expect("a source reads"); + for (n, line) in text.lines().enumerate() { + if old.iter().any(|o| line.contains(o.as_str())) { + found.push(format!("{}:{}: {}", file.display(), n + 1, line.trim())); + } + } + } + assert!( + found.is_empty(), + "messages under the old name:\n{}", + found.join("\n") + ); +} diff --git a/crates/web/src/lib.rs b/crates/web/src/lib.rs index ca7fbaeb..9f16f866 100644 --- a/crates/web/src/lib.rs +++ b/crates/web/src/lib.rs @@ -46,7 +46,7 @@ pub enum Error { #[error("listen: {0}")] Io(#[from] std::io::Error), /// The record. - #[error("amem: {0}")] + #[error("record: {0}")] Memory(#[from] dm_server::Error), } diff --git a/packaging/apparmor/amem b/packaging/apparmor/amem index 5c2afd20..90c0590a 100644 --- a/packaging/apparmor/amem +++ b/packaging/apparmor/amem @@ -16,7 +16,7 @@ # # Without a profile, `amem launch` fails at the first mapping: # -# memory: sandbox: confinement: /proc/self/setgroups: Permission denied +# amem: sandbox: confinement: /proc/self/setgroups: Permission denied # error: confinement: spawn /opt/memory/memory: Invalid argument (os error 22) # # WHAT THIS GRANTS diff --git a/spikes/harness-containers/seatbelt-steps.sh b/spikes/harness-containers/seatbelt-steps.sh index 64265a46..5405c35e 100755 --- a/spikes/harness-containers/seatbelt-steps.sh +++ b/spikes/harness-containers/seatbelt-steps.sh @@ -18,7 +18,7 @@ step() { --workdir "$work" -- "$@" "$work/.out" 2>&1 code=$? printf 'STEP %-22s exit=%s\n' "$name" "$code" - grep -v '^memory: ' "$work/.out" | sed 's/^/ /' | head -20 + grep -v '^amem: ' "$work/.out" | sed 's/^/ /' | head -20 } step true /usr/bin/true step echo /bin/echo inside From 08bfd03df2b0e06ef3899cf85ec3c48db33b8cb2 Mon Sep 17 00:00:00 2001 From: Sander Striker Date: Sat, 31 Oct 2026 15:22:14 +0100 Subject: [PATCH 3/5] test: find more spellings of the old message prefix, and fewer false ones The second adversarial pass found spellings that the test let through: no space after the colon, a tab, a leading newline escape, a single quote, and a string continued on the next line. It also found that the test refused comments and fixtures that hold the old name. Now the test finds those spellings, skips comment lines, and accepts a line that says "old name allowed". A new test holds each case. With the old list of spellings, it fails on eprintln!("memory:{e}"). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Bhj4Ck4y5iwZUsjpgQx8A2 --- crates/memory/tests/message_prefix.rs | 91 +++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 13 deletions(-) diff --git a/crates/memory/tests/message_prefix.rs b/crates/memory/tests/message_prefix.rs index 20da4706..7c0f09ba 100644 --- a/crates/memory/tests/message_prefix.rs +++ b/crates/memory/tests/message_prefix.rs @@ -1,7 +1,9 @@ -//! Every line the binary writes for a person starts with `amem:`, the command's name. -//! The demo selects the lines of `amem work` by that prefix, so a message under the old -//! name is a line the demo drops without a word. This reads the sources, since no run -//! reaches every message. +//! The binary's own messages start with `amem:`, the command's name, and none starts +//! with `memory:`, the name it had before. The demo selects the lines of `amem work` by +//! that prefix, so a message under the old name is a line the demo drops without a word. +//! This reads the sources, since no run reaches every message. It checks that the old +//! name is gone, not that every line carries the new one: `relay:`, `error:` and the +//! like are prefixes of their own. use std::path::Path; @@ -18,6 +20,76 @@ fn sources(dir: &Path, out: &mut Vec) { } } +/// Where a message under the old name starts, each as it is spelled in a source line. +fn old_spellings(name: &str) -> Vec { + // after a quote, a backtick, a byte string, or a newline escape; and what follows + // the colon is a space, a tab, a placeholder, a line continuation, or the string's end + let starts = ["\"", "'", "`", "b\"", "\\n"]; + let follows = [" ", "\\t", "{", "\\", "\""]; + let mut old = Vec::new(); + for s in starts { + for f in follows { + old.push(format!("{s}{name}:{f}")); + } + old.push(format!("{s}{name} hook:")); + } + old +} + +/// The lines of `text` that start a message under the old name. A comment is not a +/// message, and a line that says it holds the old name on purpose is let through. +fn under_the_old_name(text: &str) -> Vec<(usize, String)> { + // assembled, so this file does not hold what it looks for + let name = ["mem", "ory"].concat(); + let allowed = ["old name", " allowed"].concat(); + let old = old_spellings(&name); + let mut found = Vec::new(); + let mut continues = false; + for (n, line) in text.lines().enumerate() { + let trimmed = line.trim_start(); + let comment = trimmed.starts_with("//"); + let held = old.iter().any(|o| line.contains(o.as_str())) + || (continues && trimmed.starts_with(&format!("{name}:"))); + if held && !comment && !line.contains(&allowed) { + found.push((n + 1, trimmed.to_string())); + } + continues = !comment && line.ends_with('\\'); + } + found +} + +#[test] +fn every_spelling_of_the_old_name_is_found_and_only_those() { + let name = ["mem", "ory"].concat(); + let caught = [ + format!("eprintln!(\"{name}: x\");"), + format!("eprintln!(\"{name}:{{e}}\");"), + format!("eprintln!(\"{name}:\\tx\");"), + format!("eprintln!(\"\\n{name}: after a blank line\");"), + format!("let js = r#\"console.warn('{name}: ' + e);\"#;"), + format!("let b = b\"{name}: sandbox: \";"), + format!("eprintln!(\"{name} hook: x\");"), + ]; + for line in &caught { + assert_eq!(under_the_old_name(line).len(), 1, "missed: {line}"); + } + let continued = format!("eprintln!(\"first line\\n\\\n {name}: second line\");"); + assert_eq!( + under_the_old_name(&continued), + vec![(2, format!("{name}: second line\");"))] + ); + let passed = [ + format!("/// the `{name}: ` key"), + format!("// \"{name}: x\""), + format!("let limits = \"{name}: 1Gi\"; // old name allowed: a pod limit"), + format!("{name}: Arc,"), + "eprintln!(\"amem: x\");".to_string(), + ]; + for line in &passed { + assert!(under_the_old_name(line).is_empty(), "flagged: {line}"); + } +} + #[test] fn no_message_starts_with_the_old_name() { let crates = Path::new(env!("CARGO_MANIFEST_DIR")).join(".."); @@ -29,18 +101,11 @@ fn no_message_starts_with_the_old_name() { files.len(), crates.display() ); - // the old spellings, assembled so this file does not hold them - let old: Vec = ["\"", "`", "b\""] - .iter() - .flat_map(|q| [format!("{q}memory: "), format!("{q}memory hook:")]) - .collect(); let mut found = Vec::new(); for file in &files { let text = std::fs::read_to_string(file).expect("a source reads"); - for (n, line) in text.lines().enumerate() { - if old.iter().any(|o| line.contains(o.as_str())) { - found.push(format!("{}:{}: {}", file.display(), n + 1, line.trim())); - } + for (n, line) in under_the_old_name(&text) { + found.push(format!("{}:{n}: {line}", file.display())); } } assert!( From 260b44be5f5fd505a327a4766285440955b88232 Mon Sep 17 00:00:00 2001 From: Sander Striker Date: Mon, 2 Nov 2026 23:27:41 +0100 Subject: [PATCH 4/5] fix: skip comments and blank lines in the message prefix check The check now blanks every comment before it scans a line. A trailing comment or a block comment no longer makes the check fail. A string literal stays whole, so "//" or "/*" in a string does not start a comment. A string continuation now continues through blank lines, as in Rust. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Bhj4Ck4y5iwZUsjpgQx8A2 --- crates/memory/tests/message_prefix.rs | 120 ++++++++++++++++++++++++-- 1 file changed, 115 insertions(+), 5 deletions(-) diff --git a/crates/memory/tests/message_prefix.rs b/crates/memory/tests/message_prefix.rs index 7c0f09ba..ec502693 100644 --- a/crates/memory/tests/message_prefix.rs +++ b/crates/memory/tests/message_prefix.rs @@ -36,6 +36,85 @@ fn old_spellings(name: &str) -> Vec { old } +/// `text` with every comment blanked and every line break kept, so a line number still +/// points at its source line. A literal is kept whole: `//` or `/*` inside a string or +/// a character opens no comment. +fn without_comments(text: &str) -> String { + let chars: Vec = text.chars().collect(); + let mut out = String::with_capacity(text.len()); + let mut i = 0; + while i < chars.len() { + let rest = &chars[i..]; + if let Some(n) = comment_len(rest) { + out.extend(rest[..n].iter().map(|&c| if c == '\n' { c } else { ' ' })); + i += n; + } else { + let n = literal_len(rest).unwrap_or(1); + out.extend(&rest[..n]); + i += n; + } + } + out +} + +/// The length of the comment that `rest` starts with, if it starts with one. Block +/// comments nest. +fn comment_len(rest: &[char]) -> Option { + if rest.starts_with(&['/', '/']) { + return Some(rest.iter().position(|&c| c == '\n').unwrap_or(rest.len())); + } + if !rest.starts_with(&['/', '*']) { + return None; + } + let mut depth = 0; + let mut i = 0; + while i + 1 < rest.len() { + match (rest[i], rest[i + 1]) { + ('/', '*') => depth += 1, + ('*', '/') => depth -= 1, + _ => { + i += 1; + continue; + } + } + i += 2; + if depth == 0 { + return Some(i); + } + } + Some(rest.len()) +} + +/// The length of the string or character literal that `rest` starts with, if it starts +/// with one. A quote that no character closes is a lifetime. +fn literal_len(rest: &[char]) -> Option { + let up_to = |close: &[char], from: usize| { + rest[from..] + .windows(close.len()) + .position(|w| w == close) + .map_or(rest.len(), |p| from + p + close.len()) + }; + match rest { + ['"', ..] => { + let mut i = 1; + while i < rest.len() && rest[i] != '"' { + i += if rest[i] == '\\' { 2 } else { 1 }; + } + Some((i + 1).min(rest.len())) + } + ['r', tail @ ..] => { + let hashes = tail.iter().take_while(|&&c| c == '#').count(); + let close: Vec = std::iter::once('"') + .chain(std::iter::repeat_n('#', hashes)) + .collect(); + (tail.get(hashes) == Some(&'"')).then(|| up_to(&close, hashes + 2)) + } + ['\'', '\\', ..] => Some(up_to(&['\''], 3)), + ['\'', _, '\'', ..] => Some(3), + _ => None, + } +} + /// The lines of `text` that start a message under the old name. A comment is not a /// message, and a line that says it holds the old name on purpose is let through. fn under_the_old_name(text: &str) -> Vec<(usize, String)> { @@ -43,17 +122,21 @@ fn under_the_old_name(text: &str) -> Vec<(usize, String)> { let name = ["mem", "ory"].concat(); let allowed = ["old name", " allowed"].concat(); let old = old_spellings(&name); + let code = without_comments(text); let mut found = Vec::new(); let mut continues = false; - for (n, line) in text.lines().enumerate() { + for (n, (line, source)) in code.lines().zip(text.lines()).enumerate() { let trimmed = line.trim_start(); - let comment = trimmed.starts_with("//"); + // a continuation skips blank lines as it skips indentation + if trimmed.is_empty() { + continue; + } let held = old.iter().any(|o| line.contains(o.as_str())) || (continues && trimmed.starts_with(&format!("{name}:"))); - if held && !comment && !line.contains(&allowed) { - found.push((n + 1, trimmed.to_string())); + if held && !source.contains(&allowed) { + found.push((n + 1, source.trim_start().to_string())); } - continues = !comment && line.ends_with('\\'); + continues = line.ends_with('\\'); } found } @@ -69,6 +152,15 @@ fn every_spelling_of_the_old_name_is_found_and_only_those() { format!("let js = r#\"console.warn('{name}: ' + e);\"#;"), format!("let b = b\"{name}: sandbox: \";"), format!("eprintln!(\"{name} hook: x\");"), + // what opens a comment inside a literal opens none + format!("let s = \"//\"; eprintln!(\"{name}: x\");"), + format!("let s = \"/*\"; eprintln!(\"{name}: x\"); // */"), + format!("let s = \"a \\\" // b\"; eprintln!(\"{name}: x\");"), + format!("let s = r#\"a \" // \"#; eprintln!(\"{name}: x\");"), + format!("let q = '\"'; let s = \"//\"; eprintln!(\"{name}: x\");"), + format!("let q = '\\''; let s = \"//\"; eprintln!(\"{name}: x\");"), + format!("fn f<'a>(s: &'a str) {{ eprintln!(\"{name}: x\"); }}"), + format!("/* a note */ eprintln!(\"{name}: x\");"), ]; for line in &caught { assert_eq!(under_the_old_name(line).len(), 1, "missed: {line}"); @@ -78,9 +170,27 @@ fn every_spelling_of_the_old_name_is_found_and_only_those() { under_the_old_name(&continued), vec![(2, format!("{name}: second line\");"))] ); + // a continuation skips every blank line and all indentation that follows it + for blank in ["", " "] { + let continued = + format!("eprintln!(\"first line\\n\\\n{blank}\n {name}: second line\");"); + assert_eq!( + under_the_old_name(&continued), + vec![(3, format!("{name}: second line\");"))], + "after a line of {blank:?}" + ); + } + let after_a_block = format!("/* a note\n on two lines */ eprintln!(\"{name}: x\");"); + assert_eq!(under_the_old_name(&after_a_block).len(), 1); let passed = [ format!("/// the `{name}: ` key"), format!("// \"{name}: x\""), + format!("let x = 1; // formerly \"{name}: x\""), + format!("/* formerly \"{name}: x\" */"), + format!("let x = 1; /* \"{name}: x\" */ let y = 2;"), + format!("/* /* nested */ \"{name}: x\" */"), + format!("/*\n * formerly \"{name}: x\"\n */"), + format!("/**\n * eprintln!(\"first\\n\\\n {name}: x\");\n */"), format!("let limits = \"{name}: 1Gi\"; // old name allowed: a pod limit"), format!("{name}: Arc,"), "eprintln!(\"amem: x\");".to_string(), From 9c2485feacf7eae14faa8d08ca5fedd7db133b60 Mon Sep 17 00:00:00 2001 From: Sander Striker Date: Mon, 2 Nov 2026 23:40:13 +0100 Subject: [PATCH 5/5] test: show that a comment stops at its line, and count the messages seen A line comment that hid the rest of a file still passed both checks. A new case puts a message after a line comment. Another case puts an escaped quote in a char before a message. The check of the real sources also fails if it sees 70 or fewer messages outside comments. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Bhj4Ck4y5iwZUsjpgQx8A2 --- crates/memory/tests/message_prefix.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/memory/tests/message_prefix.rs b/crates/memory/tests/message_prefix.rs index ec502693..f86d3717 100644 --- a/crates/memory/tests/message_prefix.rs +++ b/crates/memory/tests/message_prefix.rs @@ -161,6 +161,9 @@ fn every_spelling_of_the_old_name_is_found_and_only_those() { format!("let q = '\\''; let s = \"//\"; eprintln!(\"{name}: x\");"), format!("fn f<'a>(s: &'a str) {{ eprintln!(\"{name}: x\"); }}"), format!("/* a note */ eprintln!(\"{name}: x\");"), + // a comment ends at its line, and an escaped quote in a char opens no string + format!("// a note\neprintln!(\"{name}: x\");"), + format!("let c = '\\\"'; let s = \"//\"; eprintln!(\"{name}: x\");"), ]; for line in &caught { assert_eq!(under_the_old_name(line).len(), 1, "missed: {line}"); @@ -212,12 +215,16 @@ fn no_message_starts_with_the_old_name() { crates.display() ); let mut found = Vec::new(); + let mut read = 0; for file in &files { let text = std::fs::read_to_string(file).expect("a source reads"); + read += without_comments(&text).matches("\"amem: ").count(); for (n, line) in under_the_old_name(&text) { found.push(format!("{}:{n}: {line}", file.display())); } } + // The binary has about 80 messages; far fewer seen means comments hid code. + assert!(read > 70, "only {read} messages seen outside comments"); assert!( found.is_empty(), "messages under the old name:\n{}",