{"record":{"id":"18b3cbf6fcddbe8a","repo":"headroomlabs-ai/headroom","slug":"memories-old-memory-id-and-new-memory-id-do-no","errorCode":null,"errorMessage":"Memories {old_memory.id} and {new_memory.id} do not form a reciprocal supersession edge","messagePattern":"Memories (.+?) and (.+?) do not form a reciprocal supersession edge","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/cli/memory.py","lineNumber":841,"sourceCode":"    \"\"\"Detach one incorrect OLD_ID -> NEW_ID supersession edge.\n\n    The command validates both reciprocal lineage pointers and changes no\n    neighboring edges. It is a dry run unless ``--apply`` is provided.\n\n    \\b\n    Examples:\n        headroom memory repair-supersession OLD_ID NEW_ID\n        headroom memory repair-supersession OLD_ID NEW_ID --apply\n    \"\"\"\n    _ = ctx\n    store = get_store(db_path)\n\n    try:\n        old_memory = _resolve_memory(store, old_memory_id)\n        new_memory = _resolve_memory(store, new_memory_id)\n\n        if old_memory.superseded_by != new_memory.id or new_memory.supersedes != old_memory.id:\n            raise ValueError(\n                f\"Memories {old_memory.id} and {new_memory.id} do not form \"\n                \"a reciprocal supersession edge\"\n            )\n\n        click.echo(\"\\nSupersession repair preview:\")\n        click.echo(\n            f\"  Restore old memory: {old_memory.id} \"\n            f\"({truncate(old_memory.content.replace(chr(10), ' '), 60)})\"\n        )\n        click.echo(\n            f\"  Detach new memory: {new_memory.id} \"\n            f\"({truncate(new_memory.content.replace(chr(10), ' '), 60)})\"\n        )\n        click.echo(\"  Clear: old.valid_until, old.superseded_by, new.supersedes\")\n\n        if not apply_change:\n            print_warning(\"DRY RUN: No changes made. Re-run with --apply to repair this edge.\")\n            return","sourceCodeStart":823,"sourceCodeEnd":859,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/cli/memory.py#L823-L859","documentation":"repair-supersession is a narrow maintenance command: it only detaches a broken pair where old.superseded_by == new.id AND new.supersedes == old.id (a reciprocal edge). If either side of the edge is missing or points elsewhere (half-written supersession, IDs swapped, or one side repaired already), the reciprocity check fails with this ValueError before any repair is applied.","triggerScenarios":"Running `headroom memory repair-supersession OLD NEW` where the two memories do not mutually reference each other — e.g. passing OLD/NEW in the wrong order, one of them was already detached by a previous repair, or the corruption is a different shape (one-sided superseded_by with no matching supersedes).","commonSituations":"Arguments swapped (NEW OLD instead of OLD NEW); re-running a repair that already succeeded; diagnosing an inconsistent store whose edges were partially written; copy-pasting IDs from different pairs.","solutions":["Swap the argument order and retry — OLD must be the memory whose superseded_by points at NEW","Inspect both memories first (`headroom memory show <id>`) and confirm old.superseded_by == new.id and new.supersedes == old.id","If one side is already detached, no repair is needed — re-check the store state","For other corruption shapes, use the lower-level store API or open an issue rather than forcing this command"],"exampleFix":"# before\n$ headroom memory repair-supersession NEW_ID OLD_ID\n# ValueError: Memories ... do not form a reciprocal supersession edge\n\n# after\n$ headroom memory repair-supersession OLD_ID NEW_ID","handlingStrategy":"validation","validationCode":"old = asyncio.run(store.get(old_id)) or prefix_match(old_id)\nnew = asyncio.run(store.get(new_id)) or prefix_match(new_id)\nif old.superseded_by != new.id or new.supersedes != old.id:\n    raise SystemExit(\n        \"edge not reciprocal — check argument order (OLD NEW) \"\n        f\"old.superseded_by={old.superseded_by} new.supersedes={new.supersedes}\"\n    )","typeGuard":null,"tryCatchPattern":"try:\n    run_repair(old_id, new_id)\nexcept ValueError as e:\n    if \"reciprocal supersession edge\" in str(e):\n        print(\"preconditions not met — nothing changed; inspect both memories and arg order\")\n        sys.exit(2)\n    raise","preventionTips":["Remember the argument order: OLD (superseded) first, NEW second","Inspect superseded_by/supersedes with `headroom memory show` before repairing","The check runs before any mutation — safe to retry after correcting inputs"],"tags":["cli","memory","supersession","data-integrity","valueerror"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}