{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5785e0c74cff",
   "metadata": {},
   "source": [
    "# Chapter 17: State and Consequence\n",
    "\n",
    "The request left the controller. Its acknowledgement did not return. That observation supports two different stories: the tool may have done nothing, or it may have completed the effect and lost the reply. Sending the request again can resolve the first story and damage the second. A retry counter does not tell the controller which world it occupies.\n",
    "\n",
    "This experiment gives you a local event ledger in which the actual effect and the received acknowledgement are separate fields. The ledger is constructed so the distinction can be inspected directly. In a real interface, the effect field would require an audit log, a durable receipt, or a verification query; it is not something the agent can infer from silence.\n",
    "\n",
    "The default trace contains one effect without an acknowledgement and then a repeated request. First predict the cumulative effect count. Next ask what changes if the service stores an idempotency key and binds that key to the exact payload. Finally compare the cost of a verification query with the expected cost of a blind retry. These are three separate questions: what happened, what was confirmed, and what should happen next.\n",
    "\n",
    "**Outcome:** Separate effects from acknowledgements and price a next recovery step.\n",
    "\n",
    "- Inspect the declared input contract\n",
    "- Predict the hand-checkable case\n",
    "- Run the shared computation\n",
    "- Change the critical assumption\n",
    "- Apply the method to the transfer data\n",
    "\n",
    "**Guided route:** Run the worked calculation, inspect its figure, change the stated assumption, and try the transfer case. Read the explanations beside each result before opening the answers.\n",
    "\n",
    "**Deeper route:** First read the mathematics and canonical equation reference. Audit the input contract, predict the changed result, then inspect the shared chapter implementation and solve the questions independently. Both routes use the same calculations and preserve the equations."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e84f267c215e",
   "metadata": {},
   "source": [
    "## Technical Requirements\n",
    "\n",
    "Python 3.11 or later, the complete laboratory folder, and the notebook dependencies listed in `requirements-notebooks.txt` (the launcher's **Install notebook tools** choice installs them; see START-HERE). Standard-library chapter commands also support Python 3.10. No API key, model account or network call is used by this experiment.\n",
    "\n",
    "Prior knowledge:\n",
    "\n",
    "- Python lists and dictionaries\n",
    "- Event traces and conditional probability"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eafb9aead522",
   "metadata": {},
   "source": [
    "## The question and its mathematics\n",
    "\n",
    "Let E_t count durable effects after event t, and let C_t indicate whether at least one effect has been confirmed. A request whose effect flag is true increments E_t unless a valid idempotency contract recognizes the same key and payload. Its acknowledgement changes C_t; losing that acknowledgement does not undo the effect. A verification event can confirm an effect already present in the ledger.\n",
    "\n",
    "An idempotency key is useful only if the receiving service records and checks it. Here the key maps to a payload identifier. Repeating the same pair suppresses an additional effect when idempotence is enabled. Reusing a stored key for a different payload raises an error because the requested contract is ambiguous. Counting repeated attempts without this mapping would not establish idempotence.\n",
    "\n",
    "For one unresolved request, let p denote the conditional probability that it already took effect. Let c_r be the retry cost, d the harm of a duplicate, and c_v the cost of perfect verification. A nonidempotent retry has expected next-step cost c_r+pd. With the declared idempotency contract, duplicate harm vanishes and this comparison becomes c_r against c_v. This small calculation omits the benefit and cost of any later recovery steps.\n",
    "\n",
    "The distinction between conditional belief and recorded truth matters. The trace says what happened in this constructed run; p represents what the controller believes before resolving an uncertain request. Neither quantity can replace the other in a deployed report."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94745177dac7",
   "metadata": {},
   "source": [
    "## A calculation you can run\n",
    "\n",
    "Read the trace in order. A request includes a key, payload identifier, actual effect flag, and received acknowledgement flag. A verification includes whether the existing effect was observed. The computation maintains the effect count, key ledger, confirmation status, and unresolved-effect status, then emits a row after each event. Exact boolean checks prevent strings such as \"false\" from being treated as truthy evidence.\n",
    "\n",
    "Two charts show cumulative effects and confirmation over event index. The first can rise while the second remains zero. That separation is the reason this notebook exists. A confirmation of an absent effect is rejected rather than silently accepted. The local trace is deliberately stronger than ordinary client logs because it has the ground truth needed to teach and test the inference boundary.\n",
    "\n",
    "The cost comparison uses separate declared inputs. It does not estimate the unresolved-effect probability from the trace, nor does it assume retries are independent. The changed case enables the key/payload contract while preserving the same event sequence. The transfer case replaces the retry with verification, so you can inspect how uncertainty is resolved without increasing the effect count.\n",
    "\n",
    "Once the logical effect is confirmed and no uncertainty remains, the recommended next step is stop. The verification and retry prices remain visible for inspecting the unresolved decision point; they do not justify another request after completion. Different payloads are rejected because this ledger counts duplicates of one intended logical operation.\n",
    "\n",
    "The next cell finds the bundle and imports the same computation used by the chapter skill. It does not change your system Python."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "42ebefc0e5c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "import sys, json\n",
    "LAB_ROOT = next((p for p in [Path.cwd(), *Path.cwd().parents] if (p / \"lab-manifest.json\").is_file()), None)\n",
    "if LAB_ROOT is None:\n",
    "    raise RuntimeError(\"Open this notebook from the complete extracted laboratory folder.\")\n",
    "sys.path.insert(0, str(LAB_ROOT / \"src\"))\n",
    "from math_ai_agents.core import analyze, report_text\n",
    "from math_ai_agents.plotting import figure_svg\n",
    "from IPython.display import SVG, display\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fffde8c0edb",
   "metadata": {},
   "source": [
    "Set the declared inputs below. These are constructed teaching values, not measurements from a production agent. Change a value only after predicting what it should change."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "11792583a653",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chapter 17: effect-and-retry\n",
      "Did the tool act, and should an unresolved request be verified or retried?\n",
      "Evidence: constructed teaching example\n",
      "\n",
      "Calculated quantities:\n",
      "{\n",
      "  \"effects\": 2,\n",
      "  \"duplicate_effects\": 1,\n",
      "  \"confirmed\": true,\n",
      "  \"unresolved\": false,\n",
      "  \"verification_cost\": 1.0,\n",
      "  \"retry_expected_cost\": 8.2,\n",
      "  \"preferred_next_step\": \"stop\"\n",
      "}\n",
      "\n",
      "Interpretation:\n",
      "The ledger distinguishes a real effect from receipt of its acknowledgement. Retry pricing is conditional on the supplied unresolved-effect probability.\n",
      "\n",
      "Assumptions:\n",
      "- Trace effect flags describe actual local events.\n",
      "- Idempotence requires stored key and payload equality.\n",
      "- Verification is assumed perfect for the cost comparison.\n",
      "\n",
      "Limitations:\n",
      "- No remote effect or eventual completion guarantee is inferred.\n",
      "- The comparison prices one next step, not an entire recovery policy.\n",
      "\n",
      "Execution: completed locally; constructed inputs are not deployment measurements.\n"
     ]
    }
   ],
   "source": [
    "chapter = 17\n",
    "inputs = {'idempotent': False,\n",
    " 'events': [{'kind': 'request',\n",
    "             'key': 'release-1',\n",
    "             'payload': 'edition-A',\n",
    "             'effect': True,\n",
    "             'ack': False},\n",
    "            {'kind': 'request',\n",
    "             'key': 'release-1',\n",
    "             'payload': 'edition-A',\n",
    "             'effect': True,\n",
    "             'ack': True}],\n",
    " 'verify_cost': 1,\n",
    " 'retry_cost': 0.2,\n",
    " 'effect_probability': 0.8,\n",
    " 'duplicate_cost': 10}\n",
    "report = analyze(chapter, inputs)\n",
    "# This input was explicitly taken from the teaching fixture.\n",
    "report['evidence_kind'] = 'constructed teaching example'\n",
    "print(report_text(report))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "497c46c26c41",
   "metadata": {},
   "source": [
    "The first default request produces one effect and no acknowledgement. The second produces another effect and receives an acknowledgement. The terminal ledger therefore has two effects, one duplicate relative to the intended single operation, and confirmation of at least one effect. Confirmation does not prove uniqueness.\n",
    "\n",
    "Blind retry costs 0.2+0.8(10)=8.2 in the declared next-step comparison. Verification costs 1, so at the unresolved decision point verification would be preferred. In this finished trace the second acknowledgement has already confirmed an effect, so the reported preferred_next_step is stop; the prices apply to the moment before that confirmation. Enabling idempotence suppresses the repeated same-key effect: the count stays at one and duplicate count falls to zero. The retry comparison then costs 0.2, below verification. This reversal follows from a receiving-service contract, not from the controller deciding that a retry is probably safe. Keep the key, payload, and service behavior in the evidence record.\n",
    "\n",
    "The plot below uses the calculated quantities. Read each panel's units before comparing its values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "590f57e74048",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Matplotlib is building the font cache; this may take a moment.\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" width=\"576pt\" height=\"417.6pt\" viewBox=\"0 0 576 417.6\" version=\"1.1\"><title>Calculated chapter experiment</title><desc>Labeled plot of the explicitly supplied chapter inputs. See the adjacent explanation for assumptions.</desc>\n",
       " <metadata>\n",
       "  <rdf:RDF xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n",
       "   <cc:Work>\n",
       "    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/>\n",
       "    <dc:format>image/svg+xml</dc:format>\n",
       "    <dc:creator>\n",
       "     <cc:Agent>\n",
       "      <dc:title>Mathematics of AI Agents Laboratory</dc:title>\n",
       "     </cc:Agent>\n",
       "    </dc:creator>\n",
       "   </cc:Work>\n",
       "  </rdf:RDF>\n",
       " </metadata>\n",
       " <defs>\n",
       "  <style type=\"text/css\">*{stroke-linejoin: round; stroke-linecap: butt}</style>\n",
       " </defs>\n",
       " <g id=\"figure_1\">\n",
       "  <g id=\"patch_1\">\n",
       "   <path d=\"M 0 417.6  L 576 417.6  L 576 0  L 0 0  z \" style=\"fill: #ffffff\"/>\n",
       "  </g>\n",
       "  <g id=\"axes_1\">\n",
       "   <g id=\"patch_2\">\n",
       "    <path d=\"M 47.962344 194.039062  L 565.2 194.039062  L 565.2 69.080234  L 47.962344 69.080234  z \" style=\"fill: #ffffff\"/>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_1\">\n",
       "    <g id=\"xtick_1\">\n",
       "     <g id=\"line2d_1\">\n",
       "      <defs>\n",
       "       <path id=\"m7c1177a80e\" d=\"M 0 0  L 0 3.5  \" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#m7c1177a80e\" x=\"71.473146\" y=\"194.039062\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_1\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"71.473146\" y=\"208.636719\" transform=\"rotate(-0 71.473146 208.636719)\">0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_2\">\n",
       "     <g id=\"line2d_2\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m7c1177a80e\" x=\"541.689197\" y=\"194.039062\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_2\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"541.689197\" y=\"208.636719\" transform=\"rotate(-0 541.689197 208.636719)\">1</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_3\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"306.581172\" y=\"222.6375\" transform=\"rotate(-0 306.581172 222.6375)\">event index</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_2\">\n",
       "    <g id=\"ytick_1\">\n",
       "     <g id=\"line2d_3\">\n",
       "      <path d=\"M 47.962344 188.359116  L 565.2 188.359116  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_4\">\n",
       "      <defs>\n",
       "       <path id=\"m5661ec0c8f\" d=\"M 0 0  L -3.5 0  \" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"188.359116\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_4\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"192.157944\" transform=\"rotate(-0 40.962344 192.157944)\">1.0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_2\">\n",
       "     <g id=\"line2d_5\">\n",
       "      <path d=\"M 47.962344 165.639329  L 565.2 165.639329  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_6\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"165.639329\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_5\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"169.438157\" transform=\"rotate(-0 40.962344 169.438157)\">1.2</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_3\">\n",
       "     <g id=\"line2d_7\">\n",
       "      <path d=\"M 47.962344 142.919542  L 565.2 142.919542  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_8\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"142.919542\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_6\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"146.71837\" transform=\"rotate(-0 40.962344 146.71837)\">1.4</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_4\">\n",
       "     <g id=\"line2d_9\">\n",
       "      <path d=\"M 47.962344 120.199755  L 565.2 120.199755  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_10\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"120.199755\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_7\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"123.998583\" transform=\"rotate(-0 40.962344 123.998583)\">1.6</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_5\">\n",
       "     <g id=\"line2d_11\">\n",
       "      <path d=\"M 47.962344 97.479968  L 565.2 97.479968  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_12\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"97.479968\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_8\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"101.278796\" transform=\"rotate(-0 40.962344 101.278796)\">1.8</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_6\">\n",
       "     <g id=\"line2d_13\">\n",
       "      <path d=\"M 47.962344 74.760181  L 565.2 74.760181  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_14\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"74.760181\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_9\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"78.559009\" transform=\"rotate(-0 40.962344 78.559009)\">2.0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_10\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"18.656875\" y=\"131.559648\" transform=\"rotate(-90 18.656875 131.559648)\">effect count</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"line2d_15\">\n",
       "    <path d=\"M 71.473146 188.359116  L 541.689197 74.760181  \" clip-path=\"url(#p4acd70c0ed)\" style=\"fill: none; stroke: #31586b; stroke-width: 1.8; stroke-linecap: square\"/>\n",
       "    <defs>\n",
       "     <path id=\"md7b389e114\" d=\"M 0 2  C 0.530406 2 1.03916 1.789267 1.414214 1.414214  C 1.789267 1.03916 2 0.530406 2 0  C 2 -0.530406 1.789267 -1.03916 1.414214 -1.414214  C 1.03916 -1.789267 0.530406 -2 0 -2  C -0.530406 -2 -1.03916 -1.789267 -1.414214 -1.414214  C -1.789267 -1.03916 -2 -0.530406 -2 0  C -2 0.530406 -1.789267 1.03916 -1.414214 1.414214  C -1.03916 1.789267 -0.530406 2 0 2  z \" style=\"stroke: #31586b\"/>\n",
       "    </defs>\n",
       "    <g clip-path=\"url(#p4acd70c0ed)\">\n",
       "     <use xlink:href=\"#md7b389e114\" x=\"71.473146\" y=\"188.359116\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "     <use xlink:href=\"#md7b389e114\" x=\"541.689197\" y=\"74.760181\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"patch_3\">\n",
       "    <path d=\"M 47.962344 194.039062  L 47.962344 69.080234  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_4\">\n",
       "    <path d=\"M 47.962344 194.039062  L 565.2 194.039062  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"text_11\">\n",
       "    <text style=\"font-size: 11px; font-family: 'DejaVu Sans'; text-anchor: start\" x=\"47.962344\" y=\"63.080234\" transform=\"rotate(-0 47.962344 63.080234)\">cumulative effects</text>\n",
       "   </g>\n",
       "  </g>\n",
       "  <g id=\"axes_2\">\n",
       "   <g id=\"patch_5\">\n",
       "    <path d=\"M 47.962344 375.477656  L 565.2 375.477656  L 565.2 250.518828  L 47.962344 250.518828  z \" style=\"fill: #ffffff\"/>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_3\">\n",
       "    <g id=\"xtick_3\">\n",
       "     <g id=\"line2d_16\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m7c1177a80e\" x=\"71.473146\" y=\"375.477656\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_12\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"71.473146\" y=\"390.075312\" transform=\"rotate(-0 71.473146 390.075312)\">0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_4\">\n",
       "     <g id=\"line2d_17\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m7c1177a80e\" x=\"541.689197\" y=\"375.477656\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_13\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"541.689197\" y=\"390.075312\" transform=\"rotate(-0 541.689197 390.075312)\">1</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_14\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"306.581172\" y=\"404.076094\" transform=\"rotate(-0 306.581172 404.076094)\">event index</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_4\">\n",
       "    <g id=\"ytick_7\">\n",
       "     <g id=\"line2d_18\">\n",
       "      <path d=\"M 47.962344 369.79771  L 565.2 369.79771  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_19\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"369.79771\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_15\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"373.596538\" transform=\"rotate(-0 40.962344 373.596538)\">0.0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_8\">\n",
       "     <g id=\"line2d_20\">\n",
       "      <path d=\"M 47.962344 347.077923  L 565.2 347.077923  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_21\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"347.077923\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_16\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"350.876751\" transform=\"rotate(-0 40.962344 350.876751)\">0.2</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_9\">\n",
       "     <g id=\"line2d_22\">\n",
       "      <path d=\"M 47.962344 324.358136  L 565.2 324.358136  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_23\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"324.358136\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_17\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"328.156964\" transform=\"rotate(-0 40.962344 328.156964)\">0.4</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_10\">\n",
       "     <g id=\"line2d_24\">\n",
       "      <path d=\"M 47.962344 301.638349  L 565.2 301.638349  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_25\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"301.638349\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_18\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"305.437177\" transform=\"rotate(-0 40.962344 305.437177)\">0.6</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_11\">\n",
       "     <g id=\"line2d_26\">\n",
       "      <path d=\"M 47.962344 278.918562  L 565.2 278.918562  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_27\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"278.918562\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_19\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"282.71739\" transform=\"rotate(-0 40.962344 282.71739)\">0.8</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_12\">\n",
       "     <g id=\"line2d_28\">\n",
       "      <path d=\"M 47.962344 256.198775  L 565.2 256.198775  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_29\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m5661ec0c8f\" x=\"47.962344\" y=\"256.198775\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_20\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"40.962344\" y=\"259.997603\" transform=\"rotate(-0 40.962344 259.997603)\">1.0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_21\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"18.656875\" y=\"312.998242\" transform=\"rotate(-90 18.656875 312.998242)\">confirmed flag</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"line2d_30\">\n",
       "    <path d=\"M 71.473146 369.79771  L 541.689197 256.198775  \" clip-path=\"url(#pbe49f715ad)\" style=\"fill: none; stroke: #31586b; stroke-width: 1.8; stroke-linecap: square\"/>\n",
       "    <g clip-path=\"url(#pbe49f715ad)\">\n",
       "     <use xlink:href=\"#md7b389e114\" x=\"71.473146\" y=\"369.79771\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "     <use xlink:href=\"#md7b389e114\" x=\"541.689197\" y=\"256.198775\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"patch_6\">\n",
       "    <path d=\"M 47.962344 375.477656  L 47.962344 250.518828  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_7\">\n",
       "    <path d=\"M 47.962344 375.477656  L 565.2 375.477656  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"text_22\">\n",
       "    <text style=\"font-size: 11px; font-family: 'DejaVu Sans'; text-anchor: start\" x=\"47.962344\" y=\"244.518828\" transform=\"rotate(-0 47.962344 244.518828)\">confirmation</text>\n",
       "   </g>\n",
       "  </g>\n",
       "  <g id=\"text_23\">\n",
       "   <text style=\"font-size: 12px; font-family: 'DejaVu Sans'; text-anchor: start\" x=\"46.08\" y=\"17.470125\" transform=\"rotate(-0 46.08 17.470125)\">Chapter 17: effect and retry</text>\n",
       "  </g>\n",
       " </g>\n",
       " <defs>\n",
       "  <clipPath id=\"p4acd70c0ed\">\n",
       "   <rect x=\"47.962344\" y=\"69.080234\" width=\"517.237656\" height=\"124.958828\"/>\n",
       "  </clipPath>\n",
       "  <clipPath id=\"pbe49f715ad\">\n",
       "   <rect x=\"47.962344\" y=\"250.518828\" width=\"517.237656\" height=\"124.958828\"/>\n",
       "  </clipPath>\n",
       " </defs>\n",
       "</svg>"
      ],
      "text/plain": [
       "<IPython.core.display.SVG object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "display(SVG(figure_svg(report)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76dcde816b6a",
   "metadata": {},
   "source": [
    "**Figure 17.L1:** Calculated chapter experiment. Each panel labels its input and output units; interpret it under the assumptions printed in the report."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a68d143fde1",
   "metadata": {},
   "source": [
    "## Change the assumption\n",
    "\n",
    "The most dangerous shortcut is to equate an absent acknowledgement with an absent effect. That rule encourages the controller to replay actions whose consequences may already be durable. The converse shortcut also fails: receiving an acknowledgement does not establish that only one effect occurred. The default trace ends with confirmation and a duplicate.\n",
    "\n",
    "A second failure concerns idempotency scope. A key that is checked only in client memory cannot protect against service restarts, multiple clients, or an independently repeated operation. This implementation assumes the receiver's key ledger is the effect boundary. If a real service has a retention window, payload normalization rule, or transaction boundary, those conditions must be added before adopting the simplified cost comparison.\n",
    "\n",
    "Verification has its own limitations. The comparison assumes a perfect query, while real observations can be stale or ambiguous. A false negative could provoke another retry; a false positive could terminate a workflow that never completed. Do not treat the returned recommendation as a complete recovery controller. It prices one next step under a declared conditional belief and a specific duplicate-harm contract."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4c0f9243936f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chapter 17: effect-and-retry\n",
      "Did the tool act, and should an unresolved request be verified or retried?\n",
      "Evidence: constructed changed-assumption example\n",
      "\n",
      "Calculated quantities:\n",
      "{\n",
      "  \"effects\": 1,\n",
      "  \"duplicate_effects\": 0,\n",
      "  \"confirmed\": true,\n",
      "  \"unresolved\": false,\n",
      "  \"verification_cost\": 1.0,\n",
      "  \"retry_expected_cost\": 0.2,\n",
      "  \"preferred_next_step\": \"stop\"\n",
      "}\n",
      "\n",
      "Interpretation:\n",
      "The ledger distinguishes a real effect from receipt of its acknowledgement. Retry pricing is conditional on the supplied unresolved-effect probability.\n",
      "\n",
      "Assumptions:\n",
      "- Trace effect flags describe actual local events.\n",
      "- Idempotence requires stored key and payload equality.\n",
      "- Verification is assumed perfect for the cost comparison.\n",
      "\n",
      "Limitations:\n",
      "- No remote effect or eventual completion guarantee is inferred.\n",
      "- The comparison prices one next step, not an entire recovery policy.\n",
      "\n",
      "Execution: completed locally; constructed inputs are not deployment measurements.\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" width=\"576pt\" height=\"417.6pt\" viewBox=\"0 0 576 417.6\" version=\"1.1\"><title>Calculated chapter experiment</title><desc>Labeled plot of the explicitly supplied chapter inputs. See the adjacent explanation for assumptions.</desc>\n",
       " <metadata>\n",
       "  <rdf:RDF xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n",
       "   <cc:Work>\n",
       "    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/>\n",
       "    <dc:format>image/svg+xml</dc:format>\n",
       "    <dc:creator>\n",
       "     <cc:Agent>\n",
       "      <dc:title>Mathematics of AI Agents Laboratory</dc:title>\n",
       "     </cc:Agent>\n",
       "    </dc:creator>\n",
       "   </cc:Work>\n",
       "  </rdf:RDF>\n",
       " </metadata>\n",
       " <defs>\n",
       "  <style type=\"text/css\">*{stroke-linejoin: round; stroke-linecap: butt}</style>\n",
       " </defs>\n",
       " <g id=\"figure_1\">\n",
       "  <g id=\"patch_1\">\n",
       "   <path d=\"M 0 417.6  L 576 417.6  L 576 0  L 0 0  z \" style=\"fill: #ffffff\"/>\n",
       "  </g>\n",
       "  <g id=\"axes_1\">\n",
       "   <g id=\"patch_2\">\n",
       "    <path d=\"M 54.442344 194.039062  L 565.2 194.039062  L 565.2 69.080234  L 54.442344 69.080234  z \" style=\"fill: #ffffff\"/>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_1\">\n",
       "    <g id=\"xtick_1\">\n",
       "     <g id=\"line2d_1\">\n",
       "      <defs>\n",
       "       <path id=\"m0883f7c467\" d=\"M 0 0  L 0 3.5  \" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#m0883f7c467\" x=\"77.658601\" y=\"194.039062\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_1\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"77.658601\" y=\"208.636719\" transform=\"rotate(-0 77.658601 208.636719)\">0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_2\">\n",
       "     <g id=\"line2d_2\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m0883f7c467\" x=\"541.983743\" y=\"194.039062\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_2\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"541.983743\" y=\"208.636719\" transform=\"rotate(-0 541.983743 208.636719)\">1</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_3\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"309.821172\" y=\"222.6375\" transform=\"rotate(-0 309.821172 222.6375)\">event index</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_2\">\n",
       "    <g id=\"ytick_1\">\n",
       "     <g id=\"line2d_3\">\n",
       "      <path d=\"M 54.442344 176.999222  L 565.2 176.999222  \" clip-path=\"url(#pf5f084d6db)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_4\">\n",
       "      <defs>\n",
       "       <path id=\"ma7dc00e510\" d=\"M 0 0  L -3.5 0  \" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"176.999222\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_4\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"180.79805\" transform=\"rotate(-0 47.442344 180.79805)\">0.96</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_2\">\n",
       "     <g id=\"line2d_5\">\n",
       "      <path d=\"M 54.442344 154.279435  L 565.2 154.279435  \" clip-path=\"url(#pf5f084d6db)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_6\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"154.279435\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_5\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"158.078263\" transform=\"rotate(-0 47.442344 158.078263)\">0.98</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_3\">\n",
       "     <g id=\"line2d_7\">\n",
       "      <path d=\"M 54.442344 131.559648  L 565.2 131.559648  \" clip-path=\"url(#pf5f084d6db)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_8\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"131.559648\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_6\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"135.358477\" transform=\"rotate(-0 47.442344 135.358477)\">1.00</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_4\">\n",
       "     <g id=\"line2d_9\">\n",
       "      <path d=\"M 54.442344 108.839862  L 565.2 108.839862  \" clip-path=\"url(#pf5f084d6db)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_10\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"108.839862\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_7\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"112.63869\" transform=\"rotate(-0 47.442344 112.63869)\">1.02</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_5\">\n",
       "     <g id=\"line2d_11\">\n",
       "      <path d=\"M 54.442344 86.120075  L 565.2 86.120075  \" clip-path=\"url(#pf5f084d6db)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_12\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"86.120075\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_8\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"89.918903\" transform=\"rotate(-0 47.442344 89.918903)\">1.04</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_9\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"18.774375\" y=\"131.559648\" transform=\"rotate(-90 18.774375 131.559648)\">effect count</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"line2d_13\">\n",
       "    <path d=\"M 77.658601 131.559648  L 541.983743 131.559648  \" clip-path=\"url(#pf5f084d6db)\" style=\"fill: none; stroke: #31586b; stroke-width: 1.8; stroke-linecap: square\"/>\n",
       "    <defs>\n",
       "     <path id=\"m294ada6540\" d=\"M 0 2  C 0.530406 2 1.03916 1.789267 1.414214 1.414214  C 1.789267 1.03916 2 0.530406 2 0  C 2 -0.530406 1.789267 -1.03916 1.414214 -1.414214  C 1.03916 -1.789267 0.530406 -2 0 -2  C -0.530406 -2 -1.03916 -1.789267 -1.414214 -1.414214  C -1.789267 -1.03916 -2 -0.530406 -2 0  C -2 0.530406 -1.789267 1.03916 -1.414214 1.414214  C -1.03916 1.789267 -0.530406 2 0 2  z \" style=\"stroke: #31586b\"/>\n",
       "    </defs>\n",
       "    <g clip-path=\"url(#pf5f084d6db)\">\n",
       "     <use xlink:href=\"#m294ada6540\" x=\"77.658601\" y=\"131.559648\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "     <use xlink:href=\"#m294ada6540\" x=\"541.983743\" y=\"131.559648\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"patch_3\">\n",
       "    <path d=\"M 54.442344 194.039062  L 54.442344 69.080234  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_4\">\n",
       "    <path d=\"M 54.442344 194.039062  L 565.2 194.039062  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"text_10\">\n",
       "    <text style=\"font-size: 11px; font-family: 'DejaVu Sans'; text-anchor: start\" x=\"54.442344\" y=\"63.080234\" transform=\"rotate(-0 54.442344 63.080234)\">cumulative effects</text>\n",
       "   </g>\n",
       "  </g>\n",
       "  <g id=\"axes_2\">\n",
       "   <g id=\"patch_5\">\n",
       "    <path d=\"M 54.442344 375.477656  L 565.2 375.477656  L 565.2 250.518828  L 54.442344 250.518828  z \" style=\"fill: #ffffff\"/>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_3\">\n",
       "    <g id=\"xtick_3\">\n",
       "     <g id=\"line2d_14\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m0883f7c467\" x=\"77.658601\" y=\"375.477656\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_11\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"77.658601\" y=\"390.075312\" transform=\"rotate(-0 77.658601 390.075312)\">0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_4\">\n",
       "     <g id=\"line2d_15\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m0883f7c467\" x=\"541.983743\" y=\"375.477656\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_12\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"541.983743\" y=\"390.075312\" transform=\"rotate(-0 541.983743 390.075312)\">1</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_13\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"309.821172\" y=\"404.076094\" transform=\"rotate(-0 309.821172 404.076094)\">event index</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_4\">\n",
       "    <g id=\"ytick_6\">\n",
       "     <g id=\"line2d_16\">\n",
       "      <path d=\"M 54.442344 369.79771  L 565.2 369.79771  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_17\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"369.79771\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_14\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"373.596538\" transform=\"rotate(-0 47.442344 373.596538)\">0.0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_7\">\n",
       "     <g id=\"line2d_18\">\n",
       "      <path d=\"M 54.442344 347.077923  L 565.2 347.077923  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_19\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"347.077923\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_15\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"350.876751\" transform=\"rotate(-0 47.442344 350.876751)\">0.2</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_8\">\n",
       "     <g id=\"line2d_20\">\n",
       "      <path d=\"M 54.442344 324.358136  L 565.2 324.358136  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_21\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"324.358136\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_16\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"328.156964\" transform=\"rotate(-0 47.442344 328.156964)\">0.4</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_9\">\n",
       "     <g id=\"line2d_22\">\n",
       "      <path d=\"M 54.442344 301.638349  L 565.2 301.638349  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_23\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"301.638349\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_17\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"305.437177\" transform=\"rotate(-0 47.442344 305.437177)\">0.6</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_10\">\n",
       "     <g id=\"line2d_24\">\n",
       "      <path d=\"M 54.442344 278.918562  L 565.2 278.918562  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_25\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"278.918562\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_18\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"282.71739\" transform=\"rotate(-0 47.442344 282.71739)\">0.8</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_11\">\n",
       "     <g id=\"line2d_26\">\n",
       "      <path d=\"M 54.442344 256.198775  L 565.2 256.198775  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #d4d8da; stroke-width: 0.6; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_27\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#ma7dc00e510\" x=\"54.442344\" y=\"256.198775\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_19\">\n",
       "      <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: end\" x=\"47.442344\" y=\"259.997603\" transform=\"rotate(-0 47.442344 259.997603)\">1.0</text>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"text_20\">\n",
       "     <text style=\"font-size: 10px; font-family: 'DejaVu Sans'; text-anchor: middle\" x=\"25.136875\" y=\"312.998242\" transform=\"rotate(-90 25.136875 312.998242)\">confirmed flag</text>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"line2d_28\">\n",
       "    <path d=\"M 77.658601 369.79771  L 541.983743 256.198775  \" clip-path=\"url(#pa530051428)\" style=\"fill: none; stroke: #31586b; stroke-width: 1.8; stroke-linecap: square\"/>\n",
       "    <g clip-path=\"url(#pa530051428)\">\n",
       "     <use xlink:href=\"#m294ada6540\" x=\"77.658601\" y=\"369.79771\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "     <use xlink:href=\"#m294ada6540\" x=\"541.983743\" y=\"256.198775\" style=\"fill: #31586b; stroke: #31586b\"/>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"patch_6\">\n",
       "    <path d=\"M 54.442344 375.477656  L 54.442344 250.518828  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_7\">\n",
       "    <path d=\"M 54.442344 375.477656  L 565.2 375.477656  \" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"text_21\">\n",
       "    <text style=\"font-size: 11px; font-family: 'DejaVu Sans'; text-anchor: start\" x=\"54.442344\" y=\"244.518828\" transform=\"rotate(-0 54.442344 244.518828)\">confirmation</text>\n",
       "   </g>\n",
       "  </g>\n",
       "  <g id=\"text_22\">\n",
       "   <text style=\"font-size: 12px; font-family: 'DejaVu Sans'; text-anchor: start\" x=\"46.08\" y=\"17.470125\" transform=\"rotate(-0 46.08 17.470125)\">Chapter 17: effect and retry</text>\n",
       "  </g>\n",
       " </g>\n",
       " <defs>\n",
       "  <clipPath id=\"pf5f084d6db\">\n",
       "   <rect x=\"54.442344\" y=\"69.080234\" width=\"510.757656\" height=\"124.958828\"/>\n",
       "  </clipPath>\n",
       "  <clipPath id=\"pa530051428\">\n",
       "   <rect x=\"54.442344\" y=\"250.518828\" width=\"510.757656\" height=\"124.958828\"/>\n",
       "  </clipPath>\n",
       " </defs>\n",
       "</svg>"
      ],
      "text/plain": [
       "<IPython.core.display.SVG object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "changed_inputs = {'idempotent': True,\n",
    " 'events': [{'kind': 'request',\n",
    "             'key': 'release-1',\n",
    "             'payload': 'edition-A',\n",
    "             'effect': True,\n",
    "             'ack': False},\n",
    "            {'kind': 'request',\n",
    "             'key': 'release-1',\n",
    "             'payload': 'edition-A',\n",
    "             'effect': True,\n",
    "             'ack': True}],\n",
    " 'verify_cost': 1,\n",
    " 'retry_cost': 0.2,\n",
    " 'effect_probability': 0.8,\n",
    " 'duplicate_cost': 10}\n",
    "changed = analyze(chapter, changed_inputs)\n",
    "changed['evidence_kind'] = 'constructed changed-assumption example'\n",
    "print(report_text(changed))\n",
    "display(SVG(figure_svg(changed)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dac3819b15d3",
   "metadata": {},
   "source": [
    "**Figure 17.L2:** The changed-assumption result. Compare the printed quantities and the stated assumptions with the first run. A different input need not imply a causal effect in a deployed agent."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fddf29d49cc",
   "metadata": {},
   "source": [
    "## Try a new case\n",
    "\n",
    "The transfer trace uses a request with a lost acknowledgement followed by an explicit verification. Its effect count stays at one, and confirmation becomes true at the second event. The verification cost is 0.5; blind retry would cost 0.1+0.6(4)=2.5, so at an unresolved decision point the declared comparison again favors verification. Because this trace is already confirmed, the reported preferred_next_step is stop.\n",
    "\n",
    "For reader data, preserve event order and give each effect-bearing request its durable operation identifier. If you have only client logs, mark actual effect as unknown in your measurement design instead of inventing a boolean and passing it to this deterministic replay. Obtain server evidence or construct separate possible traces. Compare those traces to identify which next observation would distinguish them. The method is useful precisely because it refuses to turn transport uncertainty into a fabricated state fact."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "82379673edde",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chapter 17: effect-and-retry\n",
      "Did the tool act, and should an unresolved request be verified or retried?\n",
      "Evidence: constructed transfer example\n",
      "\n",
      "Calculated quantities:\n",
      "{\n",
      "  \"effects\": 1,\n",
      "  \"duplicate_effects\": 0,\n",
      "  \"confirmed\": true,\n",
      "  \"unresolved\": false,\n",
      "  \"verification_cost\": 0.5,\n",
      "  \"retry_expected_cost\": 2.5,\n",
      "  \"preferred_next_step\": \"stop\"\n",
      "}\n",
      "\n",
      "Interpretation:\n",
      "The ledger distinguishes a real effect from receipt of its acknowledgement. Retry pricing is conditional on the supplied unresolved-effect probability.\n",
      "\n",
      "Assumptions:\n",
      "- Trace effect flags describe actual local events.\n",
      "- Idempotence requires stored key and payload equality.\n",
      "- Verification is assumed perfect for the cost comparison.\n",
      "\n",
      "Limitations:\n",
      "- No remote effect or eventual completion guarantee is inferred.\n",
      "- The comparison prices one next step, not an entire recovery policy.\n",
      "\n",
      "Execution: completed locally; constructed inputs are not deployment measurements.\n"
     ]
    }
   ],
   "source": [
    "transfer_inputs = {'idempotent': False,\n",
    " 'events': [{'kind': 'request',\n",
    "             'key': 'send-2',\n",
    "             'payload': 'packet-B',\n",
    "             'effect': True,\n",
    "             'ack': False},\n",
    "            {'kind': 'verify', 'observed_effect': True}],\n",
    " 'verify_cost': 0.5,\n",
    " 'retry_cost': 0.1,\n",
    " 'effect_probability': 0.6,\n",
    " 'duplicate_cost': 4}\n",
    "transfer = analyze(chapter, transfer_inputs)\n",
    "transfer['evidence_kind'] = 'constructed transfer example'\n",
    "print(report_text(transfer))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9ff158d61463",
   "metadata": {},
   "source": [
    "## Apply the method to your inputs\n",
    "\n",
    "The example file below has the exact input shape the method accepts. Copy it to a new file, replace its values, then point `reader_file` at your copy. Run the cell again. Supplied inputs retain their stated provenance; the program cannot establish that they are representative observations.\n",
    "\n",
    "- **idempotent:** Exact boolean. True declares server-side key/payload deduplication.\n",
    "- **events:** Ordered event list: request has kind,key,payload,effect:boolean,ack:boolean; verify has observed_effect:boolean. All requests must concern one logical payload; distinct operations require separate traces.\n",
    "- **verify_cost:** Nonnegative one-step cost of perfect verification.\n",
    "- **retry_cost:** Nonnegative one-step request cost.\n",
    "- **effect_probability:** Probability [0,1] that the unresolved original request already took effect.\n",
    "- **duplicate_cost:** Nonnegative extra harm from a duplicate effect."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fae4fbb4b787",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Chapter 17: effect-and-retry\n",
      "Did the tool act, and should an unresolved request be verified or retried?\n",
      "Evidence: supplied local inputs; provenance not independently verified\n",
      "\n",
      "Calculated quantities:\n",
      "{\n",
      "  \"effects\": 1,\n",
      "  \"duplicate_effects\": 0,\n",
      "  \"confirmed\": true,\n",
      "  \"unresolved\": false,\n",
      "  \"verification_cost\": 0.5,\n",
      "  \"retry_expected_cost\": 2.5,\n",
      "  \"preferred_next_step\": \"stop\"\n",
      "}\n",
      "\n",
      "Interpretation:\n",
      "The ledger distinguishes a real effect from receipt of its acknowledgement. Retry pricing is conditional on the supplied unresolved-effect probability.\n",
      "\n",
      "Assumptions:\n",
      "- Trace effect flags describe actual local events.\n",
      "- Idempotence requires stored key and payload equality.\n",
      "- Verification is assumed perfect for the cost comparison.\n",
      "\n",
      "Limitations:\n",
      "- No remote effect or eventual completion guarantee is inferred.\n",
      "- The comparison prices one next step, not an entire recovery policy.\n",
      "\n",
      "Execution: completed locally; constructed inputs are not deployment measurements.\n"
     ]
    }
   ],
   "source": [
    "reader_file = LAB_ROOT / 'data/examples/ch17.json'\n",
    "reader_inputs = json.loads(reader_file.read_text())\n",
    "reader_report = analyze(chapter, reader_inputs)\n",
    "print(report_text(reader_report))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b938b571c85e",
   "metadata": {},
   "source": [
    "## Questions\n",
    "\n",
    "1. How many effects occur in the default trace?\n",
    "\n",
    "2. What duplicate-harm value makes verification and retry tie?\n",
    "\n",
    "3. What happens when a stored idempotency key is reused with a different payload?\n",
    "\n",
    "Answers: [separate solutions](../solutions/ch17.md). Try the calculation before opening them."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0931899fb0d4",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "An action, an effect, and an acknowledgement are different events. The ledger counts effects separately from confirmation and shows how a blind retry can duplicate a completed operation. A valid idempotency contract suppresses repeated same-key, same-payload effects; a key conflict is rejected. The next-step cost comparison uses a declared unresolved-effect probability and duplicate harm. It does not guarantee recovery or infer remote state. For practical use, preserve durable identifiers, verify ambiguous consequences, and record the service-side conditions that make replay safe. A confirmed effect can still be duplicated, unauthorized, or incomplete at the workflow level.\n",
    "\n",
    "Limits of this experiment:\n",
    "\n",
    "- This is a local calculation under declared inputs, not an empirical claim about a deployed agent.\n",
    "- Read the returned assumptions and limitations before applying the numerical result.\n",
    "\n",
    "The assistant skill is [`maa-17-effect-and-retry`](../skills/maa-17-effect-and-retry/SKILL.md). It uses this notebook's tested computation and input contract."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9cc9f25ba898",
   "metadata": {},
   "source": [
    "## Equations from the chapter\n",
    "\n",
    "These are the unchanged display equations and their explanations from the canonical chapter. They are a reference for the experiment, not a claim that every equation is numerically implemented by this one method."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "330c989b5e99",
   "metadata": {},
   "source": [
    "### Equation 17.1\n",
    "\n",
    "![Equation 17.1](../assets/math/521f3b91c8104d451a8b.svg)\n",
    "\n",
    "Equation (17.1) requires repeated application to preserve the same intended effect as one application.\n",
    "\n",
    "Compare the resulting requested-effect coordinates after one application and after two, keeping the request semantics fixed.\n",
    "\n",
    "LaTeX source, preserved for inspection:\n",
    "\n",
    "```latex\n",
    "\\operatorname{eff}_{I}\\!\\big(\\operatorname{eff}(T,\\operatorname{eff}(T,x))\\big) \\;=\\; \\operatorname{eff}_{I}\\!\\big(\\operatorname{eff}(T,x)\\big)\n",
    "\\qquad\\text{for every reachable } x .\n",
    "\\tag{17.1}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f747d013377",
   "metadata": {},
   "source": [
    "### Equation 17.2\n",
    "\n",
    "![Equation 17.2](../assets/math/9fd25b8ba498db8f883f.svg)\n",
    "\n",
    "Equation (17.2) converts a missing response into a probability that the action already happened.\n",
    "\n",
    "Weigh how likely silence is when the effect landed against how likely silence is when it did not.\n",
    "\n",
    "LaTeX source, preserved for inspection:\n",
    "\n",
    "```latex\n",
    "\\mathbf{b}'(\\text{applied}) \\;=\\;\n",
    "\\frac{\\operatorname{Obs}(\\varnothing \\mid \\text{applied})\\;\\Pr(\\text{applied})}\n",
    "{\\begin{gathered}\n",
    "\\operatorname{Obs}(\\varnothing \\mid \\text{applied})\\,\\Pr(\\text{applied}) \\\\\n",
    "{}+\\; \\operatorname{Obs}(\\varnothing \\mid \\text{not applied})\\,\\Pr(\\text{not applied})\n",
    "\\end{gathered}}.\n",
    "\\tag{17.2}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74b83194ecff",
   "metadata": {},
   "source": [
    "### Equation 17.3\n",
    "\n",
    "![Equation 17.3](../assets/math/06754fe168697c58639b.svg)\n",
    "\n",
    "Equation (17.3) says whether sending the request again is worth it.\n",
    "\n",
    "Weigh the chance the action is still needed, times the cost of skipping it, against the chance it already happened, times the cost of doing it twice.\n",
    "\n",
    "LaTeX source, preserved for inspection:\n",
    "\n",
    "```latex\n",
    "\\operatorname{EU}(\\text{retry}) - \\operatorname{EU}(\\text{decline}) \\;=\\; (1-\\beta)\\,c_{\\text{miss}} \\;-\\; \\beta\\,c_{\\text{dup}} .\n",
    "\\tag{17.3}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ab889525e9f",
   "metadata": {},
   "source": [
    "### Equation 17.4\n",
    "\n",
    "![Equation 17.4](../assets/math/574a1266b01fa51afc80.svg)\n",
    "\n",
    "Equation (17.4) identifies repeat attempts whose duplicate-effect risk is resolved and whose current execution conditions have been checked.\n",
    "\n",
    "Check authority and preconditions, then require applicable idempotent semantics, proof of terminal non-application, or verified restoration after completed recovery.\n",
    "\n",
    "LaTeX source, preserved for inspection:\n",
    "\n",
    "```latex\n",
    "\\operatorname{Rep}(x) \\;=\\; \\Big\\{\\, T \\;:\\; \\operatorname{Ready}(T,x)\\;\\land\\;\\big[\\text{(17.1) holds for this request}\\;\\lor\\;\\operatorname{Absent}(T,x)\\;\\lor\\;\\operatorname{Restored}(T,x)\\big] \\,\\Big\\}.\n",
    "\\tag{17.4}\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mathematics of AI Agents",
   "language": "python",
   "name": "maa-lab"
  },
  "lab_chapter": 17,
  "lab_execution": {
   "code_cells": 6,
   "created_utc": "2026-10-02T05:15:28.475855+00:00",
   "elapsed_seconds": 8.977251874981448,
   "method": "fresh process; new ipykernel InProcessKernelManager; cells submitted as Jupyter execute requests",
   "network_transport_tested": false,
   "python": "3.11.15",
   "source_sha256": "c2b442cf8950e986ef39a43e7e4de057bab891ca60d24b5de63a6db18c76c560"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
