{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.12.14"
    },
    "execution": {
      "method": "Python subprocess, exact code cell source",
      "deterministic_replay_passed": true
    },
    "runtime": {
      "packages": [],
      "local_assets": []
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "id": "question",
      "metadata": {},
      "source": [
        "# Structured edit errors make recovery programmable\n",
        "A transactional editor can preserve source state and expose a repairable error. Syntax acceptance still says nothing about intended behavior.\n",
        "\nIn-memory parser/interface test with scripted repairs; not SWE-agent model performance.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "experiment",
      "metadata": {},
      "execution_count": 1,
      "source": [
        "\"\"\"Structured edit errors make recovery programmable\n",
        "Deterministic, standard-library experiment. RESULTS contains the full data.\n",
        "\"\"\"\n",
        "import ast\n",
        "BASE = {f'f{i}.py': f'def f{i}():\\n    return {i}\\n' for i in range(5)}\n",
        "\n",
        "def edit(files, name, start, end, replacement):\n",
        "    lines = files[name].splitlines()\n",
        "    if not 1 <= start <= end <= len(lines):\n",
        "        return {'error': 'range', 'lines': len(lines)}\n",
        "    candidate = '\\n'.join(lines[:start-1] + [replacement] + lines[end:]) + '\\n'\n",
        "    try:\n",
        "        ast.parse(candidate)\n",
        "    except SyntaxError as exc:\n",
        "        return {'error': 'syntax', 'line': exc.lineno}\n",
        "    files[name] = candidate\n",
        "    return {'ok': True}\n",
        "\n",
        "for structured in (False, True):\n",
        "    accepted = calls = 0\n",
        "    for i, name in enumerate(BASE):\n",
        "        for mistake in ('range', 'syntax'):\n",
        "            files = BASE.copy()\n",
        "            start = 99 if mistake == 'range' else 1\n",
        "            replacement = f'def f{i}():' if mistake == 'range' else f'def f{i}()'\n",
        "            for attempt in range(2):\n",
        "                before = files[name]\n",
        "                result = edit(files, name, start, start, replacement)\n",
        "                if not structured and not result.get('ok'):\n",
        "                    result = {'error': 'edit_failed'}\n",
        "                calls += 1\n",
        "                if result.get('ok'):\n",
        "                    accepted += 1\n",
        "                    break\n",
        "                assert files[name] == before\n",
        "                if structured:\n",
        "                    if result['error'] == 'range':\n",
        "                        start = min(1, result['lines'])\n",
        "                    elif result['error'] == 'syntax':\n",
        "                        replacement = f'def f{i}():'\n",
        "    print('structured=' + str(structured), 'accepted', accepted, 'calls', calls)\n",
        "    assert accepted == (10 if structured else 0)\n",
        "\n",
        "\n",
        "rows=[]\n",
        "for structured in (False,True):\n",
        "    for i,name in enumerate(BASE):\n",
        "        for mistake in ('range','syntax'):\n",
        "            files=BASE.copy(); start=99 if mistake=='range' else 1\n",
        "            replacement=f'def f{i}():' if mistake=='range' else f'def f{i}()'\n",
        "            for attempt in (1,2):\n",
        "                before=files[name]; response=edit(files,name,start,start,replacement)\n",
        "                if not structured and not response.get('ok'): response={'error':'edit_failed'}\n",
        "                rows.append(dict(policy='structured' if structured else 'generic',file=name,mistake=mistake,attempt=attempt,response=response,unchanged=files[name]==before))\n",
        "                if response.get('ok'): break\n",
        "                assert files[name]==before\n",
        "                if structured:\n",
        "                    if response['error']=='range': start=1\n",
        "                    else: replacement=f'def f{i}():'\n",
        "files=BASE.copy()\n",
        "semantic_response=edit(files,'f0.py',2,2,'    return 999')\n",
        "assert semantic_response.get('ok') and files['f0.py'] != BASE['f0.py']\n",
        "parsed=ast.parse(files['f0.py'])\n",
        "semantic_value=parsed.body[0].body[0].value.value\n",
        "assert semantic_value==999\n",
        "RESULTS=dict(attempts=rows,semantic_counterexample=dict(accepted_by_parser=True,expected_return=0,actual_return=semantic_value,semantic_test_passed=semantic_value==0))\n",
        "print('Valid syntax / wrong behavior:',semantic_value,'!=',0)\n"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "structured=False accepted 0 calls 20\n",
            "structured=True accepted 10 calls 20\n",
            "Valid syntax / wrong behavior: 999 != 0\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from pathlib import Path\n",
        "import base64\n",
        "print('__NOTEBOOK_IMAGE__svg+xml:' + base64.b64encode(Path('figure.svg').read_bytes()).decode())\n"
      ]
    }
  ]
}
