{
  "name": "Regret Log",
  "nodes": [
    {
      "id": "04eab4ca-4634-490a-ad1d-c5cc4362b3cc",
      "name": "Every Monday",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        0,
        208
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      }
    },
    {
      "id": "0776dda6-b485-4934-a9f8-74826a29d1c3",
      "name": "Load Every Approval A Human Saw",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        208
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const rows = [];\nconst spec = [\n  { category: 'Refund under 50 EUR', n: 420, overturned: 4, confidence: 0.71 },\n  { category: 'Refund over 500 EUR', n: 38, overturned: 21, confidence: 0.74 },\n  { category: 'Route ticket to a team', n: 1900, overturned: 22, confidence: 0.66 },\n  { category: 'Reply to an angry customer', n: 260, overturned: 148, confidence: 0.81 },\n  { category: 'Close duplicate ticket', n: 640, overturned: 9, confidence: 0.69 }\n];\nspec.forEach(function (s) {\n  rows.push({ category: s.category, seen: s.n, overturned: s.overturned, avg_confidence: s.confidence });\n});\nreturn [{ json: { window: 'last 90 days', decisions: rows, threshold_today: 0.95 } }];"
      }
    },
    {
      "id": "575e2261-6e58-4198-a1bd-d8deea3a02b4",
      "name": "How Often Did The Human Change Anything",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        208
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const d = $input.first().json;\nconst scored = d.decisions.map(function (c) {\n  const regret = c.overturned / c.seen;\n  let verdict = 'CALIBRATED';\n  let action = 'Leave the gate where it is.';\n  if (regret < 0.02) {\n    verdict = 'THEATRE';\n    action = 'The human changed nothing in ' + Math.round((1 - regret) * 100) + '% of cases. This gate is not review, it is a queue. Drop the threshold and let it through.';\n  } else if (regret > 0.4) {\n    verdict = 'SHOULD NOT BE AUTOMATED';\n    action = 'The human rewrote ' + Math.round(regret * 100) + '% of these. The model is not doing this job. Stop asking it to.';\n  }\n  return {\n    category: c.category, seen: c.seen, overturned: c.overturned,\n    regret_rate: Number(regret.toFixed(3)), verdict: verdict, action: action,\n    suggested_threshold: verdict === 'THEATRE' ? 0.6 : (verdict === 'SHOULD NOT BE AUTOMATED' ? 1.01 : 0.85),\n    escalations_removed_per_week: verdict === 'THEATRE' ? Math.round((c.seen - c.overturned) / 13) : 0\n  };\n});\nconst theatre = scored.filter(function (s) { return s.verdict === 'THEATRE'; });\nconst stop = scored.filter(function (s) { return s.verdict === 'SHOULD NOT BE AUTOMATED'; });\nconst saved = scored.reduce(function (a, s) { return a + s.escalations_removed_per_week; }, 0);\nconst worst = scored.slice().sort(function (a, b) { return b.regret_rate - a.regret_rate; })[0];\nconst say = 'One global approval threshold of ' + d.threshold_today + ' is applied to five very different decisions. ' +\n  theatre.length + ' of them are approval theatre - the human agreed with the model almost every time, so the gate only taught people to click Approve without reading. ' +\n  stop.length + ' should never have been automated: \\\"' + (worst ? worst.category : 'n/a') + '\\\" was rewritten ' + (worst ? Math.round(worst.regret_rate * 100) : 0) + '% of the time. ' +\n  'Setting the threshold per category instead of globally removes about ' + saved + ' pointless escalations a week and puts the attention where it changes an outcome.';\nconst headline = theatre.length > 0 ? 'theatre' : (stop.length > 0 ? 'stop' : 'calibrated');\nreturn [{ json: { plain_english: say, headline: headline, per_category: scored, escalations_removed_per_week: saved } }];"
      }
    },
    {
      "id": "ef62e5af-b00a-451b-80a8-591693c5cb45",
      "name": "What Should Change",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        760,
        208
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "theatre",
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "r1",
                    "leftValue": "={{ $json.headline }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "theatre"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "outputKey": "stop",
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "r2",
                    "leftValue": "={{ $json.headline }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "stop"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "outputKey": "calibrated",
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "r3",
                    "leftValue": "={{ $json.headline }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "calibrated"
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "dc8ceda8-9b7e-4e7b-8237-39cca2773697",
      "name": "LOWER THE GATE: Humans Are Rubber-Stamping",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1020,
        32
      ],
      "parameters": {}
    },
    {
      "id": "aaa2398d-9e3a-4f16-b670-9c386e64af90",
      "name": "PULL THE STEP: Model Is Not Doing This Job",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1020,
        208
      ],
      "parameters": {}
    },
    {
      "id": "d43c4d52-49e4-42a5-87bd-3ed02f9bb646",
      "name": "HOLD: Gate Is Earning Its Keep",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1020,
        384
      ],
      "parameters": {}
    },
    {
      "id": "0bd816cb-70bc-46b4-914e-e2d5fd493e63",
      "name": "Sticky Note 2ba665b7",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -50,
        158
      ],
      "parameters": {
        "content": "## Regret Log - the approval gate that grades itself\n\nHuman-in-the-loop is in the JD. Everyone builds it the same way: an approval node with one confidence threshold, forever.\n\nNobody measures the only number that matters - **how often did the human actually change anything?**\n\nIf the answer is 1%, that gate is not review. It is a queue that trained people to click Approve without reading, which is worse than no gate because it manufactures the *appearance* of oversight.",
        "color": 4,
        "width": 540,
        "height": 200
      }
    },
    {
      "id": "ae6103ca-c2d7-4dac-939c-e4284207728d",
      "name": "Sticky Note 44e259c9",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        430,
        158
      ],
      "parameters": {
        "content": "## Regret rate splits into three, not two\n\n- **< 2% overturned -> THEATRE.** The human adds nothing. Lower the threshold and give them their attention back.\n- **> 40% overturned -> SHOULD NOT BE AUTOMATED.** The model is not doing this job. No prompt fixes this.\n- **In between -> CALIBRATED.** The gate is working. Leave it alone.\n\nOne threshold across five different decisions is the bug. Regret rate is what lets you set five.",
        "color": 3,
        "width": 580,
        "height": 200
      }
    },
    {
      "id": "75969540-8266-42e6-8cd3-4d2d0211b8cb",
      "name": "Sticky Note 2ade8018",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        970,
        158
      ],
      "parameters": {
        "content": "## The compounding bit\n\nEvery override is a free, perfectly-labelled training example that a human already paid for.\n\nToday that signal is thrown away the moment the button is clicked. Capture it and human-in-the-loop stops being a fixed tax and starts being **the mechanism by which the system earns more autonomy.**",
        "color": 5,
        "width": 300,
        "height": 376
      }
    }
  ],
  "connections": {
    "Every Monday": {
      "main": [
        [
          {
            "node": "Load Every Approval A Human Saw",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Every Approval A Human Saw": {
      "main": [
        [
          {
            "node": "How Often Did The Human Change Anything",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "How Often Did The Human Change Anything": {
      "main": [
        [
          {
            "node": "What Should Change",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "What Should Change": {
      "main": [
        [
          {
            "node": "LOWER THE GATE: Humans Are Rubber-Stamping",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "PULL THE STEP: Model Is Not Doing This Job",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HOLD: Gate Is Earning Its Keep",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}