{"record":{"id":"c6a748947cb17efe","repo":"astrid-runtime/astrid","slug":"runtime-tree-changed-while-packed-admission-was-in","errorCode":null,"errorMessage":"runtime tree changed while packed admission was in progress","messagePattern":"runtime tree changed while packed admission was in progress","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/astrid-kernel/src/runtime_tree_admit.rs","lineNumber":101,"sourceCode":"fn admit_blocking(home: &AstridHome, store: &RuntimePrincipalStore) -> io::Result<()> {\n    let entries = scan(store, home.root())?;\n    let receipt_path = home.migrations_dir().join(RECEIPT_NAME);\n    if let Some(receipt) = read_receipt(&receipt_path)?\n        && receipt.matches_entries(&entries)\n        && catalog_contains_entries(store, &entries)?\n        && catalog_contains_receipt(store, &receipt_path)?\n    {\n        return Ok(());\n    }\n\n    store\n        .admit_runtime_tree(home.root())\n        .map_err(storage_error)?;\n    #[cfg(test)]\n    run_source_mutation_hook(home)?;\n    let after = scan(store, home.root())?;\n    if !RuntimeTreeReceipt::from_entries(&entries).matches_entries(&after) {\n        return Err(io::Error::new(\n            io::ErrorKind::WouldBlock,\n            \"runtime tree changed while packed admission was in progress\",\n        ));\n    }\n    let receipt = RuntimeTreeReceipt::from_entries(&after);\n    let bytes = serde_json::to_vec(&receipt).map_err(io::Error::other)?;\n    astrid_core::platform_fs::ensure_private_directory(&home.migrations_dir())?;\n    astrid_core::platform_fs::atomic_write_private_file(&receipt_path, &bytes)?;\n    admit_receipt(store, &receipt_path)?;\n    store\n        .establish_runtime_projection_receipt(home)\n        .map_err(storage_error)\n}\n\nfn admit_receipt(store: &RuntimePrincipalStore, receipt_path: &Path) -> io::Result<()> {\n    let name = ContentName::new(RECEIPT_RELATIVE_PATH.to_owned()).map_err(io::Error::other)?;\n    let bytes = fs::metadata(receipt_path)?.len();\n    store","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/runtime_tree_admit.rs#L83-L119","documentation":"During packed admission, the kernel scans the runtime tree before and after admitting it, and requires the receipt digest to be stable. If `RuntimeTreeReceipt::from_entries` computed from the pre-scan does not match the post-scan entries, the tree was mutated concurrently and the operation aborts with WouldBlock instead of persisting a torn view.","triggerScenarios":"`admit_blocking` (called via `admit`) observes `!before.matches_entries(&after)` — files were added/removed/modified in the runtime tree between the two scans, including the test-only source mutation hook.","commonSituations":"Another app instance or CLI command writing to the home concurrently; a sync tool changing files mid-admission; the user moving files while the app starts up.","solutions":["Retry the admission operation once the tree is quiescent (WouldBlock signals a safe retry)","Close other running instances of the app before admitting","Pause file sync/indexing tools that touch the home directory","Serialize home-mutating operations through a single process/lock"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match err.downcast_ref::<io::Error>() {\n    Some(e) if e.kind() == io::ErrorKind::WouldBlock => {\n        std::thread::sleep(Duration::from_millis(200));\n        retry_admit()?; // safe: nothing was persisted\n    }\n    _ => return Err(err),\n}","preventionTips":["Ensure single-writer access to the home (one app instance, one CLI invocation)","Exclude the home from live sync/indexing tools","Acquire your own lock around home-mutating operations"],"tags":["concurrency","race-condition","retry"],"backgroundTag":"invalid-state-transition","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}