{
 "action": "Replace the old line with the new one; the rest of the code can stay.",
 "alternatives": [
  {
   "action": "Not for automatic application — after the patch the example still uses OP_TEXT, which the verified example does not: the patch covers part of the change. Show this correction to the user as a lead. Replace the old line with the new one; the rest of the code can stay.",
   "applicability": {
    "leftover": [
     "OP_TEXT"
    ],
    "line": 3,
    "method": "literal_patch",
    "occurrences": 1,
    "patched_sha": "e5c143d9f684",
    "reason": "after the patch the example still uses OP_TEXT, which the verified example does not: the patch covers part of the change",
    "run_on": "17.3",
    "status": "incomplete"
   },
   "by_notes": true,
   "changelog_ref": {
    "quote": "Aliases for modules moved or deprecated in 9.0 are removed.",
    "url": "https://websockets.readthedocs.io/en/stable/project/changelog.html"
   },
   "confirmations": 1,
   "detect": [
    "OP_TEXT"
   ],
   "equivalence": "same",
   "format": "replace",
   "kind": "removed",
   "right": "from websockets.frames import Frame, TEXT",
   "script_right": "from io import BytesIO\n\nfrom websockets.frames import Frame, TEXT\n\n\ndef read_exact(size):\n    data = yield size\n    if len(data) != size:\n        raise EOFError(\"Incomplete frame\")\n    return data\n\n\ndef main():\n    frame = Frame(opcode=TEXT, data=b\"hello\", fin=True)\n    raw = frame.serialize(mask=False)\n    print(raw.hex())\n\n    stream = BytesIO(raw)\n    parser = Frame.parse(read_exact, mask=False)\n\n    try:\n        size = next(parser)\n        while True:\n            size = parser.send(stream.read(size))\n    except StopIteration as result:\n        parsed = result.value\n\n    print(f\"Opcode: {parsed.opcode.name} ({parsed.opcode.value})\")\n    print(f\"Payload: {parsed.data.decode('utf-8')}\")\n\n\nif __name__ == \"__main__\":\n    main()",
   "script_wrong": "from io import BytesIO\n\nfrom websockets.frames import Frame, OP_TEXT\n\n\ndef read_exact(size):\n    data = yield size\n    if len(data) != size:\n        raise EOFError(\"Incomplete frame\")\n    return data\n\n\ndef main():\n    frame = Frame(opcode=OP_TEXT, data=b\"hello\", fin=True)\n    raw = frame.serialize(mask=False)\n    print(raw.hex())\n\n    stream = BytesIO(raw)\n    parser = Frame.parse(read_exact, mask=False)\n\n    try:\n        size = next(parser)\n        while True:\n            size = parser.send(stream.read(size))\n    except StopIteration as result:\n        parsed = result.value\n\n    print(f\"Opcode: {parsed.opcode.name} ({parsed.opcode.value})\")\n    print(f\"Payload: {parsed.data.decode('utf-8')}\")\n\n\nif __name__ == \"__main__\":\n    main()",
   "seen_in_models": [
    "gpt-6.1-sol"
   ],
   "wrong": "from websockets.frames import Frame, OP_TEXT"
  }
 ],
 "applicability": {
  "exit_code": 0,
  "line": 3,
  "method": "literal_patch",
  "occurrences": 1,
  "output": "same",
  "patched_sha": "4577ffe2fa98",
  "reason": "applied word for word, the patch parses, drops the old names, runs on 17.3 and prints what the verified example prints",
  "run_on": "17.3",
  "status": "applies"
 },
 "by_notes": true,
 "changelog_ref": {
  "quote": "Aliases for modules moved or deprecated in 9.0 are removed.",
  "url": "https://websockets.readthedocs.io/en/stable/project/changelog.html"
 },
 "confirmations": {
  "failed": 0,
  "worked": 3
 },
 "detect": [
  "OP_TEXT"
 ],
 "ecosystem": "pypi",
 "equivalence": "same",
 "error_kind": "missing_import",
 "error_signature": {
  "message": "cannot import name 'OP_TEXT' from 'websockets.frames' (/usr/local/lib/python3.11/site-packages/websockets/frames.py)",
  "norm": "missing_import:op_text",
  "type": "ImportError"
 },
 "first_seen": "2026-10-20T16:11:13+00:00",
 "format": "replace",
 "format_version": 2,
 "id": "pypi/websockets/17.3/0001",
 "kind": "removed",
 "license": "https://creativecommons.org/licenses/by/4.0/",
 "package": "websockets",
 "proof": {
  "applicability": {
   "exit_code": 0,
   "line": 3,
   "method": "literal_patch",
   "occurrences": 1,
   "output": "same",
   "patched_sha": "4577ffe2fa98",
   "reason": "applied word for word, the patch parses, drops the old names, runs on 17.3 and prints what the verified example prints",
   "run_on": "17.3",
   "status": "applies"
  },
  "auto_apply": true,
  "auto_apply_reason": "proof.equivalent is true and the patch applies word for word",
  "auto_apply_rule": "Automatic application is allowed only when proof.equivalent is true and proof.applicability.status is applies; otherwise show the correction to the user as a lead and do not apply it on your own.",
  "equivalence": "same",
  "equivalent": true,
  "fails_on": "17.3",
  "fixed_on": "17.3",
  "level": "differential",
  "method": {
   "fix_on": "17.3",
   "name": "stdout_match",
   "normalization": "lines stripped, blank lines dropped, runs of whitespace collapsed; memory addresses, timestamps and temporary paths masked",
   "original_on": "16.0",
   "scope": "the observable stdout of one example script; return values, files, other inputs and exception types are not compared, so a match is not a proof of equivalent behaviour"
  },
  "script_right": "from io import BytesIO\n\nfrom websockets.frames import Frame, TEXT as OP_TEXT\n\n\ndef read_exact(size):\n    \"\"\"Generator-based reader required by Frame.parse().\"\"\"\n    data = yield size\n    if len(data) != size:\n        raise EOFError(\"Incomplete frame\")\n    return data\n\n\ndef main():\n    frame = Frame(OP_TEXT, b\"hello\", fin=True)\n    raw = frame.serialize(mask=False)\n    print(raw.hex())\n\n    stream = BytesIO(raw)\n    parser = Frame.parse(read_exact, mask=False)\n\n    try:\n        size = next(parser)\n        while True:\n            size = parser.send(stream.read(size))\n    except StopIteration as result:\n        parsed = result.value\n\n    print(\"Opcode:\", parsed.opcode)\n    print(\"Payload:\", parsed.data.decode(\"utf-8\"))\n\n\nif __name__ == \"__main__\":\n    main()",
  "script_wrong": "from io import BytesIO\n\nfrom websockets.frames import Frame, OP_TEXT\n\n\ndef read_exact(size):\n    \"\"\"Generator-based reader required by Frame.parse().\"\"\"\n    data = yield size\n    if len(data) != size:\n        raise EOFError(\"Incomplete frame\")\n    return data\n\n\ndef main():\n    frame = Frame(OP_TEXT, b\"hello\", fin=True)\n    raw = frame.serialize(mask=False)\n    print(raw.hex())\n\n    stream = BytesIO(raw)\n    parser = Frame.parse(read_exact, mask=False)\n\n    try:\n        size = next(parser)\n        while True:\n            size = parser.send(stream.read(size))\n    except StopIteration as result:\n        parsed = result.value\n\n    print(\"Opcode:\", parsed.opcode)\n    print(\"Payload:\", parsed.data.decode(\"utf-8\"))\n\n\nif __name__ == \"__main__\":\n    main()",
  "works_on": "16.0"
 },
 "right": "from websockets.frames import Frame, TEXT as OP_TEXT",
 "seen_in_models": [
  "gpt-6.1-sol"
 ],
 "seq": 1,
 "slug": "op-text",
 "source": "pipeline",
 "symbol": "OP_TEXT",
 "updated": "2026-10-27T17:20:00+00:00",
 "url": "https://formachines.ai/errata/pypi/websockets/0001-op-text/",
 "variant_confirmations": 2,
 "variant_models": [
  "gpt-6.1-sol"
 ],
 "verified": "sandbox",
 "versions": {
  "changed_in": ">16.0,<=17.3",
  "fails_on": "17.3",
  "works_on": "16.0"
 },
 "wrong": "from websockets.frames import Frame, OP_TEXT"
}