From 2c3b513b17e377eeefe234e453fd9db531d1663a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 16 Sep 2026 16:52:26 +0200 Subject: [PATCH] Pin that a resumed session keeps its stored text (L1 c3.s1.f3) Ruling L1-Q7 (a) persisted the instruction text so that editing a lens's text in code neither breaks nor alters an in-flight session, but no test proved a resume reads the stored text. The new test takes a real refused row, rewrites it as a later build would find it (stored text differs from the recorded lens's current text, invocation prepared under the stored text), pushes it through the real store file, reopens, and resumes with a fresh runner. Every inference after the resume carries the stored text, the session commits under the same command id, and the row still records the stored text and the drawn lens. It pins resume only; nothing ties stored text to the recorded lens, which remains a recorded cost. Test-only; no production code changes. Co-Authored-By: Claude Opus 5 --- crates/ghostlight/src/controllers.rs | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/crates/ghostlight/src/controllers.rs b/crates/ghostlight/src/controllers.rs index 05e8397..c7a697e 100644 --- a/crates/ghostlight/src/controllers.rs +++ b/crates/ghostlight/src/controllers.rs @@ -10351,6 +10351,86 @@ mod tests { ); } + /// A session resumes with the text it stored, not the text its lens authors + /// now (ruling L1-Q7 (a)): a lens-text edit in code neither breaks nor alters + /// an in-flight session. A real refused row is rewritten as a later build + /// would find it, its stored text no longer the recorded lens's current text + /// and its invocation prepared under the stored text; the store is reopened + /// and a fresh runner resumes it. Every inference after the resume carries + /// the stored text, and the session commits under the same command id with + /// that text still recorded. This pins resume only; nothing here ties the + /// stored text to the recorded lens. + #[tokio::test] + async fn a_resumed_session_keeps_its_stored_text_when_the_lens_text_changes() { + const STORED: &str = "STORED TEXT an earlier build authored"; + let (directory, mailbox, task, commons, road) = elaboration_mailbox().await; + let jurisdiction = JurisdictionKey::PlaceSubtree(commons); + let script = shed_script(road); + let recording = fresh_store(); + let first = elaboration_runner(&mailbox, script.clone(), recording.clone()); + assert_eq!( + first.step(jurisdiction).await.unwrap(), + crate::elaboration::ElaborationOutcome::Rejected + ); + drop(first); + let refused = { + let stored = recording.work.lock().unwrap(); + let ControllerWork::Elaboration( + checkpoint @ ElaborationCheckpoint::ElaboratorInFlight { .. }, + ) = stored.values().next().unwrap().clone() + else { + panic!("the refusal did not reopen the session"); + }; + checkpoint + }; + let lens = recorded_session(&ControllerWork::Elaboration(refused.clone())).lens; + assert_ne!(lens.instructions(), STORED); + let earlier = with_texts(&refused, STORED, STORED); + assert!(earlier.integrity_is_valid()); + let command_id = earlier.command_id(); + + let store = Arc::new( + open_with_raw_row( + &directory, + "controller-work.cc", + &earlier, + CONTROLLER_WORK_ROW, + CONTROLLER_WORK_SCHEMA, + ) + .expect("the earlier build's row opens"), + ); + let resumed_from = script.seen.lock().unwrap().len(); + let second = elaboration_runner(&mailbox, script.clone(), store.clone()); + assert_eq!( + second.step(jurisdiction).await.unwrap(), + crate::elaboration::ElaborationOutcome::Committed + ); + drop(second); + { + let seen = script.seen.lock().unwrap(); + assert!(seen.len() > resumed_from, "the resume ran no inference"); + for invocation in &seen[resumed_from..] { + assert_eq!( + invocation.invocation.request.instructions, STORED, + "the resume rebuilt the text from the lens" + ); + } + } + { + let journal = store.journal.lock().unwrap(); + assert_eq!(journal.work.len(), 1, "the resume opened a second row"); + let work = journal.work.get(&command_id).expect("the same command id"); + let session = recorded_session(work); + assert_eq!(session.lens, lens); + assert_eq!(session.instructions, STORED); + } + assert!(mailbox.snapshot().await.unwrap().boundaries.is_empty()); + + drop(store); + drop(mailbox); + task.await.unwrap(); + } + /// A real lensed in-flight payload under the previous row version is /// refused at open and not migrated; the same payload under the current /// version opens, so the refusal is the version's.