{
  "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": [
        "# Memory needs a scope: a rule-change test inspired by Reflexion\n",
        "A 30-episode trace shows why the conditions attached to a failure note matter more than the size of the notebook.\n",
        "\nDeterministic note-retrieval extension; no LLM reflection or Reflexion score replication.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "experiment",
      "metadata": {},
      "execution_count": 1,
      "source": [
        "\"\"\"Memory needs a scope: a rule-change test inspired by Reflexion\n",
        "Deterministic, standard-library experiment. RESULTS contains the full data.\n",
        "\"\"\"\n",
        "EPISODES = [(1 if i < 15 else 2, 'B' if i < 15 else 'A')\n",
        "            for i in range(30)]\n",
        "\n",
        "def evaluate(mode):\n",
        "    notes = []\n",
        "    wins = invalid = abstained = 0\n",
        "    history = []\n",
        "    for version, correct in EPISODES:\n",
        "        applicable = [n for n in notes if mode == 'permanent'\n",
        "                      or (mode == 'versioned' and n['version'] == version)]\n",
        "        blocked = {n['avoid'] for n in applicable}\n",
        "        lane = next((x for x in ('A', 'B') if x not in blocked), None)\n",
        "        success = lane == correct\n",
        "        wins += success\n",
        "        if lane is None:\n",
        "            abstained += 1\n",
        "        elif not success:\n",
        "            invalid += 1\n",
        "            if mode != 'none':\n",
        "                notes.append(dict(version=version, avoid=lane))\n",
        "        history.append(int(success))\n",
        "    assert wins + invalid + abstained == 30\n",
        "    return wins, invalid, abstained, sum(history[:15]), sum(history[15:])\n",
        "\n",
        "print('policy: wins invalid abstained first_half second_half')\n",
        "for mode in ('none', 'permanent', 'versioned'):\n",
        "    print(mode, *evaluate(mode))\n",
        "assert evaluate('versioned')[0] == 29\n",
        "assert evaluate('permanent')[2] == 14\n",
        "\n",
        "\n",
        "rows = []\n",
        "for mode in ('none','permanent','versioned'):\n",
        "    notes = []\n",
        "    for episode,(version,correct) in enumerate(EPISODES,1):\n",
        "        active = [n for n in notes if mode == 'permanent' or (mode == 'versioned' and n['version'] == version)]\n",
        "        blocked = {n['avoid'] for n in active}\n",
        "        lane = next((x for x in ('A','B') if x not in blocked),None)\n",
        "        outcome = 'abstained' if lane is None else ('completed' if lane==correct else 'invalid')\n",
        "        rows.append(dict(policy=mode,episode=episode,version=version,correct=correct,choice=lane,blocked=sorted(blocked),outcome=outcome))\n",
        "        if outcome=='invalid' and mode!='none': notes.append(dict(version=version,avoid=lane))\n",
        "assert sum(r['outcome']=='completed' for r in rows if r['policy']=='versioned')==29\n",
        "RESULTS=dict(episodes=rows, totals={p:dict(zip(('completed','invalid','abstained','first_half','second_half'),evaluate(p))) for p in ('none','permanent','versioned')})\n",
        "print('Episode-level audit:',len(rows),'policy–episode records')\n"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "policy: wins invalid abstained first_half second_half\n",
            "none 15 15 0 0 15\n",
            "permanent 14 2 14 14 0\n",
            "versioned 29 1 0 14 15\n",
            "Episode-level audit: 90 policy–episode records\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"
      ]
    }
  ]
}
