{"record":{"id":"433cc77d294bba0b","repo":"AprilNEA/OpenLogi","slug":"relationship-verification-failed-fixture-case-names-map-to","errorCode":null,"errorMessage":"relationship verification failed: fixture case names map to the same file","messagePattern":"relationship verification failed: fixture case names map to the same file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/openlogi-cli/src/cmd/fixture/verify.rs","lineNumber":131,"sourceCode":"                \"fixture structure verification failed: fixture directory has no manifest.json\",\n            )?,\n            profile: profile.context(\n                \"fixture structure verification failed: fixture directory has no profile.json\",\n            )?,\n            cases,\n        })\n    }\n}\n\nfn load_cassettes(\n    cases_directory: Option<&Path>,\n    manifest: &FixtureManifest,\n) -> Result<Vec<HidCassette>> {\n    let mut expected = BTreeMap::new();\n    for case in &manifest.cases {\n        let file_name = case_file_name(&case.name)?;\n        if expected.insert(file_name, case.name.as_str()).is_some() {\n            bail!(\"relationship verification failed: fixture case names map to the same file\");\n        }\n    }\n\n    if expected.is_empty() {\n        if cases_directory.is_some() {\n            bail!(\n                \"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\")?;","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/AprilNEA/OpenLogi/blob/e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8/crates/openlogi-cli/src/cmd/fixture/verify.rs#L113-L149","documentation":"While loading a fixture, `load_cassettes` derives the on-disk file name for each declared case (`case_file_name(&case.name)`). Because every case must map to a distinct cassette file, two cases producing the same file name means the manifest is inconsistent; the BTreeMap insert collision triggers this bail. It throws to prevent silently loading one cassette under two manifest entries.","triggerScenarios":"Declaring two fixture cases in the manifest whose names normalize/escape to the same file name — e.g. `\"case one\"` and `\"case-one\"` or `\"Case/1\"` vs `\"case_1\"` both collapsing to the same sanitized file name, or literally duplicate case names.","commonSituations":"Hand-editing the manifest and adding a near-duplicate case name; renaming a case but leaving the old entry; copy-pasting a manifest block without changing the name; a sanitizer that maps distinct names to one slug.","solutions":["Find the two cases in the manifest whose names collide and rename one so its derived file name is unique","Remove the genuinely duplicate case entry","Check the name sanitization (case, spaces, separators) to confirm which names collapse, then pick distinct slugs"],"exampleFix":"// before (manifest)\ncases = [\"scroll-up\", \"scroll up\"]   // both -> scroll-up.toml\n// after\ncases = [\"scroll-up\", \"scroll-down\"]","handlingStrategy":"validation","validationCode":"# pre-check: manifest case names must derive to unique file names\npython3 -c \"import sys,collections; names=open('manifest.txt').read().split(); fs=[slug(n) for n in names]; d=[k for k,v in collections.Counter(fs).items() if v>1]; sys.exit(f'duplicate derived names: {d}' and 2)\"","typeGuard":null,"tryCatchPattern":"match load(fixture_dir) {\n    Err(e) if e.to_string().contains(\"case names map to the same file\") => {\n        eprintln!(\"Rename one of the colliding cases in the manifest, then retry.\");\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Use unique, distinct slugs for case names (avoid names differing only by spaces/case/separators)","After editing the manifest, diff case names against the previous version","Run `openlogi fixture verify` locally before committing manifest changes"],"tags":["fixture","manifest","naming-collision"],"backgroundTag":"file-already-exists","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"}