From 8703059cc68eb0f06978fb851d8e63a4dcbb63fb Mon Sep 17 00:00:00 2001 From: MrScripty Date: Tue, 3 Nov 2026 10:15:07 -0700 Subject: [PATCH 1/2] fix(library): identify truncated GGUF files without failing their import The v0.8.0 rehearsal on 89bb2f54 failed intermittently in two places that had passed on the previous run: - Linux: a .gguf too short for its 24-byte header (here a 17-byte file with no GGUF magic, picked by extension) made identification return a raw "failed to fill whole buffer" I/O error. When the watcher's background import reached it first, the owned import failed and shutdown reported incomplete work. Truncated content is now identified as a GGUF of unknown type, so validation reports the unusable file; genuine read failures are still errors. A regression test covers both the no-magic and truncated-header cases. - macOS: a discovery test expected a successor owner the instant the previous one dropped, while a child spawned by a parallel test can briefly inherit the native store lock. The test now retries only that busy refusal for up to five seconds, as local_start_authority already waits for release. Co-Authored-By: Claude Opus 5.5 --- rust/crates/pumas-core/src/discovery/tests.rs | 27 ++++++++++++--- .../src/model_library/identifier.rs | 33 +++++++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/rust/crates/pumas-core/src/discovery/tests.rs b/rust/crates/pumas-core/src/discovery/tests.rs index 4385ac0a..08508f46 100644 --- a/rust/crates/pumas-core/src/discovery/tests.rs +++ b/rust/crates/pumas-core/src/discovery/tests.rs @@ -503,12 +503,29 @@ async fn ordinary_drop_retains_owner_until_real_finite_index_mutation_and_ipc_se .is_err()); // This diagnostic handle still owns the mutable library after settlement. drop(primary); - let successor = attach_or_start( - registry.clone(), - &root, - &CompatibilityRequirements::default(), - ) + // Dropping the owner does not release the native store lock immediately: + // a child spawned by a parallel test can briefly inherit its descriptor. + // Only that busy refusal is retried, within a bound. + let successor = tokio::time::timeout(std::time::Duration::from_secs(5), async { + loop { + match attach_or_start( + registry.clone(), + &root, + &CompatibilityRequirements::default(), + ) + .await + { + Err(crate::PumasError::InvalidParams { message }) + if message.contains("already running for physical store") => + { + tokio::time::sleep(std::time::Duration::from_millis(20)).await; + } + other => break other, + } + } + }) .await + .expect("physical store lease was not released after the owner dropped") .unwrap(); assert!(matches!(&successor, LocalAccess::Owned { .. })); successor.shutdown_owned().await.unwrap(); diff --git a/rust/crates/pumas-core/src/model_library/identifier.rs b/rust/crates/pumas-core/src/model_library/identifier.rs index 2dbdb88c..d0025d4f 100644 --- a/rust/crates/pumas-core/src/model_library/identifier.rs +++ b/rust/crates/pumas-core/src/model_library/identifier.rs @@ -209,8 +209,20 @@ fn identify_gguf(file: &mut R, path: &Path) -> Result {} + // Too short for a GGUF header: malformed content, not a failed read. + // Validation reports the unusable file; import must not fail on it. + Err(error) if error.kind() == std::io::ErrorKind::UnexpectedEof => { + return Ok(ModelTypeInfo { + format: FileFormat::Gguf, + model_type: ModelType::Unknown, + family: None, + extra: HashMap::new(), + }); + } + Err(error) => return Err(PumasError::io_with_path(error, path)), + } let version = u32::from_le_bytes(header[4..8].try_into().unwrap()); let metadata_count = u64::from_le_bytes(header[16..24].try_into().unwrap()); @@ -1033,6 +1045,23 @@ pub fn extract_gguf_metadata(path: impl AsRef) -> Result Date: Tue, 3 Nov 2026 10:38:23 -0700 Subject: [PATCH 2/2] test(runtime): await physical store release after a confirmed child drain PR CI failed once in the headless suite: right after the parked child was drained, an immediate nonblocking acquisition of the physical store still saw Busy. A child forked by a parallel test briefly holds an inherited copy of the lock until its exec closes it, as the store lifetime tests already document and wait for. The post-drain check now waits up to five seconds for release; the earlier check that the store is still retained while the child is unresolved is unchanged. Co-Authored-By: Claude Opus 5.5 --- .../src/runtime_profiles/process_owner.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/rust/crates/pumas-core/src/runtime_profiles/process_owner.rs b/rust/crates/pumas-core/src/runtime_profiles/process_owner.rs index b4d6844d..7639e258 100644 --- a/rust/crates/pumas-core/src/runtime_profiles/process_owner.rs +++ b/rust/crates/pumas-core/src/runtime_profiles/process_owner.rs @@ -1329,7 +1329,19 @@ mod tests { assert!(custody.drain(Duration::from_secs(5)).unwrap()); assert!(!custody.is_active()); assert!(!custody.has_parked_child()); - let after_confirmed_drain = PhysicalStoreLease::try_acquire(&store); + // A child forked by a parallel test briefly holds an inherited copy of + // the lock until its exec closes it, so release is awaited (bounded). + let release_deadline = std::time::Instant::now() + Duration::from_secs(5); + let after_confirmed_drain = loop { + let attempt = PhysicalStoreLease::try_acquire(&store); + if !matches!(&attempt, Err(StoreLeaseError::Busy(_))) + || std::time::Instant::now() >= release_deadline + { + break attempt; + } + drop(attempt); + std::thread::sleep(Duration::from_millis(10)); + }; assert!( after_confirmed_drain.is_ok(), "confirmed fixture drain did not release physical store: {after_confirmed_drain:?}"