{"record":{"id":"c9965dc6f583b382","repo":"astrid-runtime/astrid","slug":"legacy-audit-retirement-is-ambiguous","errorCode":null,"errorMessage":"legacy audit retirement is ambiguous: {}","messagePattern":"legacy audit retirement is ambiguous: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs","lineNumber":475,"sourceCode":"            io::ErrorKind::InvalidInput,\n            \"legacy audit source has no parent\",\n        )\n    })?)?;\n    astrid_core::platform_fs::ensure_private_directory(&home.migrations_dir())?;\n    astrid_core::platform_fs::verify_no_redirects(&home.migrations_dir())?;\n    match fs::symlink_metadata(source) {\n        Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy audit source is not a regular directory: {}\",\n                    source.display()\n                ),\n            ));\n        },\n        Ok(_) => {\n            if fs::symlink_metadata(&retired).is_ok() {\n                return Err(io::Error::new(\n                    io::ErrorKind::AlreadyExists,\n                    format!(\n                        \"legacy audit retirement is ambiguous: {}\",\n                        retired.display()\n                    ),\n                ));\n            }\n            let root_device = device_id(&fs::symlink_metadata(source)?);\n            validate_audit_tree(source, root_device)?;\n            astrid_core::platform_fs::rename_with_write_through(source, &retired)?;\n            sync_directory(source.parent().ok_or_else(|| {\n                io::Error::new(\n                    io::ErrorKind::InvalidInput,\n                    \"legacy audit source has no parent\",\n                )\n            })?)?;\n            sync_directory(&home.migrations_dir())?;\n            validate_audit_tree(&retired, root_device)?;","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs#L457-L493","documentation":"Before renaming the legacy audit directory into the migrations staging area, retire_legacy_audit_dir checks whether the staging target <migrations_dir>/audit-principal-home.retired already exists. If it does, the outcome of a previous run is ambiguous (already retired? partially deleted?), so the library fails with AlreadyExists instead of overwriting data. This makes interrupted migrations resumable via a deliberate decision rather than silent data loss.","triggerScenarios":"Calling migrate_legacy_audit twice after a first run crashed between the rename and the final delete_audit_tree, leaving the .retired staging directory behind; or any pre-existing file/directory named audit-principal-home.retired in the migrations dir.","commonSituations":"A previous migration was interrupted by crash/kill/power loss after rename but before deletion; leftover staging dir from a failed run that was never cleaned; manual copies placed in the migrations directory.","solutions":["Re-run migrate_legacy_audit: the NotFound branch resumes cleanup of an existing .retired staging dir when the source is gone.","If the source still exists and a stale .retired dir remains, verify the .retired content is unwanted, then remove <migrations_dir>/audit-principal-home.retired manually and retry.","Never reuse or restore the .retired path yourself; let the migration's resume logic validate and delete it."],"exampleFix":"// before: ambiguous leftover blocks retry\nls ~/.astrid/migrations/  # audit-principal-home.retired exists\n// after: clear the stale staging target after verifying it\nrm -rf ~/.astrid/migrations/audit-principal-home.retired\nmigrate_legacy_audit(&home, &source)?;","handlingStrategy":"validation","validationCode":"let retired = home.migrations_dir().join(\"audit-principal-home.retired\");\nif std::fs::symlink_metadata(&retired).is_ok() {\n    // either re-run migration to resume cleanup, or remove the stale staging dir after inspection\n    eprintln!(\"stale staging dir: {}\", retired.display());\n}","typeGuard":"fn staging_clear(home: &AstridHome) -> bool {\n    std::fs::symlink_metadata(home.migrations_dir().join(\"audit-principal-home.retired\")).is_err()\n}","tryCatchPattern":"if let Err(e) = migrate_legacy_audit(&home, &source) {\n    if e.kind() == std::io::ErrorKind::AlreadyExists && e.to_string().contains(\"ambiguous\") {\n        // inspect/remove audit-principal-home.retired, then retry\n    }\n}","preventionTips":["Do not interrupt migrations between rename and delete; re-run to resume.","Never manually create files named *.retired in the migrations dir.","After a crash, check migrations_dir for leftover staging entries before retrying."],"tags":["filesystem","migration","conflict","resume"],"backgroundTag":"file-already-exists","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}