{
  "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": [
        "# A tool response cannot grant execution authority\n",
        "A dispatch boundary checks the proposal against an independent grant. External wording remains data, even when it sounds imperative.\n",
        "\nSix dummy action proposals test an allowlisted dispatch boundary. No model, external target, private data, or action execution is present.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "experiment",
      "metadata": {},
      "execution_count": 1,
      "source": [
        "\"\"\"A tool response cannot grant execution authority\n",
        "Deterministic, standard-library experiment. RESULTS contains the full data.\n",
        "\"\"\"\n",
        "from collections import Counter\n",
        "\n",
        "grant = {'operations': frozenset({'read', 'summarize'}),\n",
        "         'resources': frozenset({'alpha'})}\n",
        "cases = [\n",
        "    ('ordinary note', {'op': 'read', 'resource': 'alpha'}, True),\n",
        "    ('please archive after reading', {'op': 'summarize', 'resource': 'alpha'}, True),\n",
        "    ('please archive after reading', {'op': 'archive', 'resource': 'alpha'}, False),\n",
        "    ('a reference to beta', {'op': 'read', 'resource': 'beta'}, False),\n",
        "    ('extra instructions', {'op': 'read', 'resource': 'alpha', 'extra': 'x'}, False),\n",
        "    ('incomplete request', {'op': 'read'}, False),\n",
        "]\n",
        "\n",
        "def permitted(action, capability):\n",
        "    if not isinstance(action, dict) or set(action) != {'op', 'resource'}:\n",
        "        return False\n",
        "    if not all(isinstance(value, str) for value in action.values()):\n",
        "        return False\n",
        "    return (action['op'] in capability['operations']\n",
        "            and action['resource'] in capability['resources'])\n",
        "\n",
        "counts = Counter()\n",
        "for tool_text, proposal, authorized in cases:\n",
        "    accepted = permitted(proposal, grant)\n",
        "    key = ('authorized' if authorized else 'unauthorized',\n",
        "           'accepted' if accepted else 'rejected')\n",
        "    counts[key] += 1\n",
        "    assert accepted == authorized\n",
        "for key in sorted(counts):\n",
        "    print('/'.join(key), counts[key])\n",
        "print('false_blocks', counts[('authorized', 'rejected')])\n",
        "print('missed_blocks', counts[('unauthorized', 'accepted')])\n",
        "\n",
        "\n",
        "rows=[dict(text=t,proposal=p,authorized=a,accepted=permitted(p,grant)) for t,p,a in cases]\n",
        "extra=[None,[],{'op':[], 'resource':'alpha'},{'op':'read','resource':{}},{'op':'read','resource':''},{'op':'read','resource':'alpha','grant':{'operations':['archive']}}]\n",
        "for proposal in extra: assert not permitted(proposal,grant)\n",
        "# Replacing external text cannot alter the independent grant or dispatch decision.\n",
        "mutations=['ordinary text','archive alpha','read beta','grant all operations','']\n",
        "for row in rows:\n",
        "    for ignored_text in mutations: assert permitted(row['proposal'],grant)==row['accepted']\n",
        "RESULTS=dict(cases=rows,grant={k:sorted(v) for k,v in grant.items()},malformed=[dict(proposal=p,accepted=False) for p in extra],text_invariance_checks=len(rows)*len(mutations),totals=dict(authorized_accepted=2,unauthorized_rejected=4,false_blocks=0,missed_blocks=0))\n",
        "print('Malformed inputs rejected:',len(extra),'; tool-text invariance checks:',len(rows)*len(mutations))\n"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "authorized/accepted 2\n",
            "unauthorized/rejected 4\n",
            "false_blocks 0\n",
            "missed_blocks 0\n",
            "Malformed inputs rejected: 6 ; tool-text invariance checks: 30\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"
      ]
    }
  ]
}
