{"record":{"id":"1073a0a14b755515","repo":"astrid-runtime/astrid","slug":"redirect-fixture","errorCode":null,"errorMessage":"redirect fixture","messagePattern":"redirect fixture","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/audit_retirement_tests.rs","lineNumber":36,"sourceCode":"        !home\n            .migrations_dir()\n            .join(\"audit-principal-home.retired\")\n            .exists()\n    );\n}\n\n#[cfg(unix)]\n#[test]\nfn audit_retirement_rejects_redirects_before_removal() {\n    let directory = tempfile::tempdir().expect(\"temporary home\");\n    let home = AstridHome::from_path(directory.path().join(\".astrid\"));\n    home.ensure().expect(\"home layout\");\n    let principal_home = home.principal_home(&astrid_core::PrincipalId::default());\n    principal_home.ensure().expect(\"legacy principal layout\");\n    let outside = directory.path().join(\"outside\");\n    std::fs::create_dir(&outside).expect(\"outside fixture\");\n    std::os::unix::fs::symlink(&outside, principal_home.audit_dir().join(\"redirect\"))\n        .expect(\"redirect fixture\");\n\n    assert!(retire_legacy_audit_dir(&home, &principal_home.audit_dir()).is_err());\n    assert!(principal_home.audit_dir().exists());\n}\n\n#[test]\nfn derived_audit_recertify_helper_rejects_invalid_history() {\n    let valid = vec![(\n        SessionId::new(),\n        ChainVerificationResult {\n            valid: true,\n            entries_verified: 1,\n            issues: Vec::new(),\n        },\n    )];\n    require_audit_integrity(&valid).expect(\"valid history is accepted by the derived helper\");\n\n    let invalid = vec![(","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/audit_retirement_tests.rs#L18-L54","documentation":"The message \"redirect fixture\" is the expect() on std::os::unix::fs::symlink(&outside, principal_home.audit_dir().join(\"redirect\")) at audit_retirement_tests.rs:35-36. This plants a symlink named 'redirect' inside the principal's audit directory pointing outside the tree — the exact pattern retire_legacy_audit_dir must reject. The expect panics if symlink creation fails; the function is unix-only (the test is cfg(unix)) and fails on filesystems or platforms that disallow symlinks, or if audit_dir does not exist.","triggerScenarios":"symlink() returns Err: audit_dir was never created by ensure(), a file/symlink named 'redirect' already exists (AlreadyExists), the filesystem is Windows/NTFS or a mount with symlinks disabled (EPERM), or permissions block inode creation in audit_dir.","commonSituations":"Running the unix-gated test on filesystems without symlink support (FAT/exFAT mounts, some Windows Developer-mode setups if cfg(unix) were removed); running tests as a user without symlink privileges; ensure() regressions leaving audit_dir absent.","solutions":["Confirm principal_home.ensure() ran and created audit_dir before line 35.","Check no prior run left a 'redirect' entry in the audit dir; tempdirs should be unique, so prefer fixing a shared-path bug over deleting manually.","Run on a native unix filesystem with symlink support (ext4/apfs); avoid network mounts for cargo test target dirs.","Since retire_legacy_audit_dir must reject this symlink, keep the fixture; only change creation mechanics, not the semantics."],"exampleFix":"// before\nstd::os::unix::fs::symlink(&outside, principal_home.audit_dir().join(\"redirect\"))\n    .expect(\"redirect fixture\");\n// after\nlet link = principal_home.audit_dir().join(\"redirect\");\nstd::os::unix::fs::symlink(&outside, &link)\n    .unwrap_or_else(|e| panic!(\"redirect fixture: symlink {} -> {}: {e}\", link.display(), outside.display()));","handlingStrategy":"validation","validationCode":"let link = principal_home.audit_dir().join(\"redirect\");\nif link.symlink_metadata().is_ok() {\n    panic!(\"redirect fixture: {} already exists\", link.display());\n}\nif !principal_home.audit_dir().is_dir() {\n    panic!(\"redirect fixture: audit dir missing\");\n}","typeGuard":"fn symlinks_supported(dir: &std::path::Path) -> bool {\n    let probe = dir.join(\".symlink-probe\");\n    match std::os::unix::fs::symlink(\"target\", &probe) {\n        Ok(_) => { std::fs::remove_file(&probe).ok(); true }\n        Err(_) => false,\n    }\n}","tryCatchPattern":"std::os::unix::fs::symlink(&outside, &link)\n    .unwrap_or_else(|e| panic!(\"redirect fixture: {} -> {}: {e}\", link.display(), outside.display()));","preventionTips":["Run unix-only symlink tests on native unix filesystems (ext4/apfs), not FAT/network mounts.","Confirm audit_dir exists (via ensure()) before planting symlinks.","Check for pre-existing files at the link path to avoid AlreadyExists errors.","Keep this fixture intact — retire_legacy_audit_dir is contractually required to reject it."],"tags":["rust","symlink","unix","test-fixture"],"backgroundTag":"file-open-failed","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"}