{"record":{"id":"8db0228451096baa","repo":"AprilNEA/OpenLogi","slug":"relationship-verification-failed-missing-declared-fixture","errorCode":null,"errorMessage":"relationship verification failed: missing declared fixture case file {missing:?}","messagePattern":"relationship verification failed: missing declared fixture case file (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/openlogi-cli/src/cmd/fixture/verify.rs","lineNumber":165,"sourceCode":"    let mut found = BTreeMap::new();\n    for entry in read_directory(directory, \"fixture cases directory\")? {\n        require_regular_file(&entry, \"fixture cassette\")?;\n        let file_name = entry_name(&entry)?;\n        let Some(case_name) = expected.get(&file_name) else {\n            bail!(\"relationship verification failed: undeclared fixture case file {file_name:?}\");\n        };\n        let cassette: HidCassette = read_json(&entry.path(), \"HID cassette\")?;\n        if cassette.name != *case_name {\n            bail!(\n                \"relationship verification failed: cassette file {file_name:?} contains case {:?}\",\n                cassette.name\n            );\n        }\n        found.insert(file_name, cassette);\n    }\n\n    if let Some(missing) = expected.keys().find(|name| !found.contains_key(*name)) {\n        bail!(\"relationship verification failed: missing declared fixture case file {missing:?}\");\n    }\n    Ok(found.into_values().collect())\n}\n\nfn case_file_name(case_name: &str) -> Result<String> {\n    if matches!(case_name, \".\" | \"..\") || case_name.contains('/') || case_name.contains('\\\\') {\n        bail!(\n            \"relationship verification failed: fixture case name {case_name:?} is not a safe file name\"\n        );\n    }\n    Ok(format!(\"{case_name}.json\"))\n}\n\nfn require_directory_id(directory: &Path, fixture_id: &str) -> Result<()> {\n    if directory.file_name().and_then(|name| name.to_str()) == Some(fixture_id) {\n        Ok(())\n    } else {\n        bail!(","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/AprilNEA/OpenLogi/blob/e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8/crates/openlogi-cli/src/cmd/fixture/verify.rs#L147-L183","documentation":"After scanning the fixture directory, a case declared in the manifest has no corresponding `*.json` cassette file on disk (checked via `expected.keys().find(|name| !found.contains_key(name))`). The verifier treats every declared case as required, so a declared-but-absent cassette fails relationship verification.","triggerScenarios":"Running `openlogi fixture verify` when the fixture manifest lists a case whose `case_file_name(case).json` file is missing from the fixture directory — e.g. the cassette was deleted or never recorded while the manifest still declares it.","commonSituations":"A cassette `.json` was removed or renamed by hand or by an incomplete merge; a new case was added to the manifest before its cassette was captured; `.gitignore` or a bad git checkout dropped the file.","solutions":["Create or re-record the missing cassette file `<case-name>.json` inside the fixture directory.","If the case is no longer needed, remove its entry from the fixture manifest so declarations and files agree.","Check git status/history to see if the cassette was accidentally deleted or ignored, and restore it.","Re-run `openlogi fixture verify`."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let declared: Vec<String> = manifest_cases();\nfor case in &declared {\n    let f = format!(\"{case}.json\");\n    assert!(fixture_dir.join(&f).is_file(), \"declared case file missing: {f}\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always add the manifest entry and the cassette file in the same commit","Run `openlogi fixture verify` before pushing fixture changes","Check .gitignore/packaging rules so generated cassettes are not excluded"],"tags":["fixture","verification","missing-file","manifest"],"backgroundTag":"file-not-found","analyzedSha":"e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8","analyzedAt":"2026-09-13T03:07:16.451Z","contentChangedAt":"2026-09-13T03:07:16.451Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}