{"record":{"id":"0ce151d12cca7ede","repo":"affaan-m/ECC","slug":"native-snapshot-identity-mismatch","errorCode":null,"errorMessage":"native snapshot identity mismatch","messagePattern":"native snapshot identity mismatch","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/integration.py","lineNumber":213,"sourceCode":"        raise ValueError(\"native snapshot must be an object\")\n    settings = snapshot.get(\"settings\")\n    native_fps = settings.get(\"timelineFrameRate\") if isinstance(settings, dict) else None\n    # Resolve's conventional decimal NTSC labels represent these exact rates.\n    ntsc = {\"23.976\": \"24000/1001\", \"29.97\": \"30000/1001\", \"59.94\": \"60000/1001\"}\n    try:\n        if type(native_fps) not in (str, int, float):\n            raise ValueError(\"native fps missing\")\n        label = str(native_fps)\n        if not re.fullmatch(r\"[0-9]{1,9}(?:\\.[0-9]{1,12}|/[1-9][0-9]{0,8})?\", label):\n            raise ValueError(\"native fps must use a bounded decimal or rational label\")\n        native_rate = Fraction(ntsc.get(label, label))\n        if native_rate != Fraction(*_rate(baseline[\"fps\"])):\n            raise ValueError(\"native fps differs\")\n    except (ValueError, ZeroDivisionError) as exc:\n        raise ValueError(\"native snapshot fps is missing, invalid or contradictory\") from exc\n    for cfg, key in [(\"project_name\", \"project\"), (\"timeline_name\", \"timeline\")]:\n        if _text(baseline[cfg]) != snapshot.get(key):\n            raise ValueError(\"native snapshot identity mismatch\")\n    tracks = snapshot.get(\"timeline_readback\")\n    if not isinstance(tracks, dict) or not tracks:\n        raise ValueError(\"native clip snapshot required\")\n    for track, clips in tracks.items():\n        if not re.fullmatch(r\"(?:video|audio)[1-9][0-9]*\", track) or not isinstance(clips, list):\n            raise ValueError(\"invalid native snapshot track\")\n        for clip in clips:\n            _check_clip(clip, bounds)\n    return tracks\n\n\ndef _check_clip(clip: Any, bounds: list[int]) -> None:\n    required = {\"path\", \"name\", \"start\", \"end\", \"left_offset\", \"right_offset\", \"enabled\", \"properties\"}\n    if not isinstance(clip, dict) or not required <= clip.keys():\n        raise ValueError(\"native snapshot clip is incomplete\")\n    _range([clip[\"start\"], clip[\"end\"]], bounds)\n    _integer(clip[\"left_offset\"])\n    _integer(clip[\"right_offset\"])","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/integration.py#L195-L231","documentation":"_snapshot verifies the snapshot belongs to the same edit: snapshot['project'] must equal baseline.project_name and snapshot['timeline'] must equal baseline.timeline_name (compared after _text normalization). A mismatch means the native snapshot documents a different project or timeline than the request claims, so insert proposals would be bound to the wrong timeline.","triggerScenarios":"build_application_bundle where baseline.project_name/timeline_name differ from snapshot's project/timeline strings, or snapshot lacks those keys (get returns None).","commonSituations":"Renaming a timeline in Resolve after the request was authored; pointing the request at the wrong snapshot file; duplicating a timeline (copy named 'T v2'); a snapshot exported from a different project with the same timeline name pattern.","solutions":["Update baseline.project_name/timeline_name to exactly match the snapshot's project/timeline values (including version suffixes like 'Timeline 1 v2').","Re-export the snapshot from the project/timeline the request targets.","If the timeline was renamed, regenerate the request config with the new name.","Whitespace matters only for emptiness — verify exact string equality, including case and spacing."],"exampleFix":"// before\nbaseline.timeline_name = \"main\"; snapshot: {\"timeline\": \"main v2\"}\n\n// after\nbaseline.timeline_name = \"main v2\" (or re-export snapshot for \"main\")","handlingStrategy":"validation","validationCode":"def identity_matches(baseline, snapshot):\n    return (snapshot.get(\"project\") == baseline[\"project_name\"]\n            and snapshot.get(\"timeline\") == baseline[\"timeline_name\"])","typeGuard":"def is_bound_snapshot(baseline, snapshot) -> bool:\n    return isinstance(snapshot, dict) and snapshot.get(\"project\") == baseline.get(\"project_name\") and snapshot.get(\"timeline\") == baseline.get(\"timeline_name\")","tryCatchPattern":"try:\n    bundle = build_application_bundle(config, None, local_only=True)\nexcept ValueError as exc:\n    if \"identity mismatch\" in str(exc):\n        print(\"snapshot project/timeline do not match baseline names\")\n    raise","preventionTips":["Regenerate the request config whenever a timeline is renamed.","Check for version suffixes like 'Timeline 1 v2' after duplicating timelines.","Store the snapshot next to a manifest of the project/timeline it came from.","Compare names exactly, including case and whitespace."],"tags":["identity","mismatch","snapshot"],"backgroundTag":"checksum-mismatch","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}