diff --git a/crates/worker-runtime/src/worker_backend.rs b/crates/worker-runtime/src/worker_backend.rs index 19233e5f..2b1123c8 100644 --- a/crates/worker-runtime/src/worker_backend.rs +++ b/crates/worker-runtime/src/worker_backend.rs @@ -2824,7 +2824,7 @@ mod tests { #[tokio::test] #[serial_test::serial(worker_allocation)] - async fn restore_pending_workspace_worker_without_system_prompt_fails_closed() { + async fn restore_legacy_workspace_worker_without_manifest_snapshot_requires_replacement() { let root = tempfile::tempdir().unwrap(); let runtime_store_dir = root.path().join("runtime"); let worker_ref = WorkerRef::new(crate::identity::WorkerId::from_legacy_u64(1)); @@ -2833,32 +2833,6 @@ mod tests { .join(worker_ref.worker_id.to_string()); let worker_name = ProfileRuntimeWorkerFactory::runtime_worker_name_for_ref(&worker_ref); let session_id = session_store::new_session_id(); - let manifest = manifest::WorkerManifest::from_toml(&format!( - r#" - [worker] - name = "{}" - pwd = "{}" - - [model] - scheme = "anthropic" - model_id = "test-model" - auth = {{ kind = "none" }} - - [engine] - max_tokens = 100 - - [feature.flow] - enabled = true - - [[scope.allow]] - target = "{}" - permission = "write" - "#, - worker_name, - root.path().display(), - root.path().display(), - )) - .unwrap(); WorkerAggregateStore::new(&worker_aggregate_dir, &worker_name) .unwrap() .set_active( @@ -2866,7 +2840,7 @@ mod tests { Some(session_store::WorkerActiveSegmentRef::pending_segment( session_id, )), - Some(serde_json::to_value(&manifest).unwrap()), + None, ) .unwrap(); @@ -2899,10 +2873,10 @@ mod tests { }) .await { - Ok(_) => panic!("pending Workspace Worker restore unexpectedly succeeded"), + Ok(_) => panic!("legacy Workspace Worker restore unexpectedly succeeded"), Err(error) => error, }; - assert!(error.contains("requires operation-owned launch material")); + assert!(error.contains("replacement Worker is required"), "{error}"); } #[tokio::test] diff --git a/crates/worker/src/worker.rs b/crates/worker/src/worker.rs index 01f9c0c9..2ebac04a 100644 --- a/crates/worker/src/worker.rs +++ b/crates/worker/src/worker.rs @@ -4819,6 +4819,13 @@ where .ok_or_else(|| WorkerError::WorkerMetadataMissing { worker_name: worker_name.to_string(), })?; + if workspace_context.workspace_id().is_some() + && metadata.resolved_manifest_snapshot.is_none() + { + return Err(WorkerError::WorkerMetadataManifestSnapshotMissing { + worker_name: worker_name.to_string(), + }); + } let active = metadata .active .ok_or_else(|| WorkerError::WorkerMetadataInactive { @@ -4868,6 +4875,13 @@ where .ok_or_else(|| WorkerError::WorkerMetadataMissing { worker_name: worker_name.to_string(), })?; + if workspace_context.workspace_id().is_some() + && metadata.resolved_manifest_snapshot.is_none() + { + return Err(WorkerError::WorkerMetadataManifestSnapshotMissing { + worker_name: worker_name.to_string(), + }); + } let active = metadata .active .ok_or_else(|| WorkerError::WorkerMetadataInactive { @@ -5769,7 +5783,9 @@ pub enum WorkerError { session_id: SessionId, }, - #[error("worker metadata for {worker_name} does not include a resolved manifest snapshot")] + #[error( + "worker metadata for {worker_name} does not include a trusted resolved manifest snapshot; a replacement Worker is required" + )] WorkerMetadataManifestSnapshotMissing { worker_name: String }, #[error(