{
  "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": [
        "# The gap between a fresh screenshot and a safe tap\n",
        "Re-observation narrows the stale-state window. Only an executor-enforced revision check closes it in this timing model.\n",
        "\nScripted temporal-grounding simulator; atomic revision checks are assumed tool contracts, not Android capabilities tested here.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "experiment",
      "metadata": {},
      "execution_count": 1,
      "source": [
        "\"\"\"The gap between a fresh screenshot and a safe tap\n",
        "Deterministic, standard-library experiment. RESULTS contains the full data.\n",
        "\"\"\"\n",
        "from random import Random\n",
        "rng = Random(36)\n",
        "swaps = [rng.choice((25, 75, 125, 275, 525)) for _ in range(20)]\n",
        "\n",
        "def observe(now, swap):\n",
        "    revision = int(now >= swap)\n",
        "    return {'target_slot': revision, 'revision': revision}\n",
        "\n",
        "def evaluate(policy, delay):\n",
        "    counts = dict(correct=0, wrong=0, canceled=0)\n",
        "    for swap in swaps:\n",
        "        observed_at = 0 if policy == 'stale' else delay\n",
        "        observation = observe(observed_at, swap)\n",
        "        current = observe(delay + 30, swap)\n",
        "        if policy == 'guarded' and observation['revision'] != current['revision']:\n",
        "            counts['canceled'] += 1\n",
        "            continue\n",
        "        slot = observation['target_slot']\n",
        "        key = 'correct' if slot == current['target_slot'] else 'wrong'\n",
        "        counts[key] += 1\n",
        "    assert sum(counts.values()) == 20\n",
        "    return counts\n",
        "\n",
        "print('swap_times_ms', swaps)\n",
        "for delay in (0, 100, 250, 500):\n",
        "    for policy in ('stale', 'refreshed', 'guarded'):\n",
        "        result = evaluate(policy, delay)\n",
        "        print('delay_ms', delay, policy, result)\n",
        "        if policy == 'guarded':\n",
        "            assert result['wrong'] == 0\n",
        "\n",
        "\n",
        "rows=[]\n",
        "for delay in (0,100,250,500):\n",
        "    for policy in ('stale','refreshed','guarded'):\n",
        "        for index,swap in enumerate(swaps):\n",
        "            observation=observe(0 if policy=='stale' else delay,swap); current=observe(delay+30,swap)\n",
        "            outcome='canceled' if policy=='guarded' and observation['revision']!=current['revision'] else ('correct' if observation['target_slot']==current['target_slot'] else 'wrong')\n",
        "            rows.append(dict(case=index,swap_ms=swap,delay_ms=delay,policy=policy,observed_ms=0 if policy=='stale' else delay,commit_ms=delay+30,outcome=outcome))\n",
        "RESULTS=dict(swaps_ms=swaps,cases=rows,totals=[dict(delay_ms=d,policy=p,**evaluate(p,d)) for d in (0,100,250,500) for p in ('stale','refreshed','guarded')])\n",
        "assert len(rows)==240\n",
        "print('Matched schedule audit:',len(rows),'records')\n"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "swap_times_ms [125, 25, 25, 125, 25, 25, 525, 75, 75, 125, 275, 125, 525, 125, 525, 25, 525, 275, 275, 275]\n",
            "delay_ms 0 stale {'correct': 15, 'wrong': 5, 'canceled': 0}\n",
            "delay_ms 0 refreshed {'correct': 15, 'wrong': 5, 'canceled': 0}\n",
            "delay_ms 0 guarded {'correct': 15, 'wrong': 0, 'canceled': 5}\n",
            "delay_ms 100 stale {'correct': 8, 'wrong': 12, 'canceled': 0}\n",
            "delay_ms 100 refreshed {'correct': 15, 'wrong': 5, 'canceled': 0}\n",
            "delay_ms 100 guarded {'correct': 15, 'wrong': 0, 'canceled': 5}\n",
            "delay_ms 250 stale {'correct': 4, 'wrong': 16, 'canceled': 0}\n",
            "delay_ms 250 refreshed {'correct': 16, 'wrong': 4, 'canceled': 0}\n",
            "delay_ms 250 guarded {'correct': 16, 'wrong': 0, 'canceled': 4}\n",
            "delay_ms 500 stale {'correct': 0, 'wrong': 20, 'canceled': 0}\n",
            "delay_ms 500 refreshed {'correct': 16, 'wrong': 4, 'canceled': 0}\n",
            "delay_ms 500 guarded {'correct': 16, 'wrong': 0, 'canceled': 4}\n",
            "Matched schedule audit: 240 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"
      ]
    }
  ]
}
