{"record":{"id":"33e1748aa03b3c4a","repo":"AprilNEA/OpenLogi","slug":"relationship-verification-failed-cassette-file-file-name","errorCode":null,"errorMessage":"relationship verification failed: cassette file {file_name:?} contains case {:?}","messagePattern":"relationship verification failed: cassette file (.+?) contains case (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/openlogi-cli/src/cmd/fixture/verify.rs","lineNumber":156,"sourceCode":"                \"relationship verification failed: profile-only fixture has an undeclared cases directory\"\n            );\n        }\n        return Ok(Vec::new());\n    }\n    let directory = cases_directory.context(\n        \"relationship verification failed: manifest declares cases but the cases directory is missing\",\n    )?;\n\n    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        );","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/AprilNEA/OpenLogi/blob/e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8/crates/openlogi-cli/src/cmd/fixture/verify.rs#L138-L174","documentation":"During fixture relationship verification, a cassette JSON file present in the fixture directory was read successfully, but its internal `name` field does not match the case name declared in the fixture manifest. The verifier requires each cassette file's embedded case name to agree exactly with the manifest's declaration for that file. This catches renamed cases whose on-disk files were not regenerated in step.","triggerScenarios":"Running `openlogi fixture verify` (via `load_cassettes`, called from `load`) when a `*.json` HID cassette in the fixture directory declares a `name` that differs from the manifest case mapped to that filename by `case_file_name` (e.g. the manifest entry was renamed but the cassette JSON still carries the old name).","commonSituations":"A developer renames a fixture case in the manifest (or in code that generates it) without editing the cassette file's `name` field; hand-edited cassettes copied from another fixture; a merge kept the new filename with the old file content.","solutions":["Open the cassette JSON at the reported file path and set its `name` field to the case name declared in the fixture manifest.","Regenerate the cassette files with the fixture authoring/record tooling so names and files are rewritten together.","If the case name in the manifest is wrong, update the manifest entry (and its directory id if needed) to match the cassette's actual name.","Re-run `openlogi fixture verify` to confirm the corpus is consistent."],"exampleFix":"// before (case.json)\n{ \"name\": \"bolt-smartshift-old\", ... }\n// after\n{ \"name\": \"bolt-smartshift\", ... }","handlingStrategy":"validation","validationCode":"let cassette: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(path)?)?;\nlet name = cassette[\"name\"].as_str().ok_or(\"cassette missing name\")?;\nassert_eq!(name, expected_case_name, \"cassette name {name} != manifest case {expected_case_name}\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Regenerate cassette files through tooling whenever a case is renamed, never edit the name field by hand","Add a CI/verify step that cross-checks cassette `name` fields against the manifest","Keep case names and filenames derived from a single source of truth via case_file_name"],"tags":["fixture","verification","cli","consistency"],"backgroundTag":"schema-validation-failed","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"}