{"slug": "can-your-ai-model-survive-its-own-mistakes", "title": "Can your AI model survive its own mistakes?", "summary": "Tapoo, a browser-based behaviour profiler from developer dmigwi, puts AI models through a maze navigation challenge to measure whether they can survive their own mistakes, charging each turn against a fixed budget of decay units equal to the number of maze cells. The tool records every decision and builds a capability-and-violation profile against the Tapoo Agentic Behavior Rubric, with models classified by traversal speed as backtrackers (below 1.0000x), navigators (exactly 1.0000x), or trailblazers (above 1.0000x). Tapoo runs entirely in the browser with no server, and logs stay on the user's device.", "body_md": "Model releases lead with their highest achievements, but almost none document how a model performs when a prompt is incomplete or ambiguous, or what it does once its own errors start piling up. Tapoo is a behaviour profiler built for exactly that: it puts a model under structured uncertainty, records every decision it makes, and builds a profile - a fingerprint of observed capabilities and violations - of how it copes.\n\n**Survival is computed -** Every turn is charged against a fixed budget; batching several correct moves into one turn\nearns part of that budget back; and a model survives its own mistakes exactly when what its batching earns covers what\nits errors cost. When it does not, the run is already unwinnable at any pace ever observed, with budget still in hand\n\n- and Tapoo names the turn.\n\n**Try it live, in your browser - nothing to install:**\n\n- **Tapoo** -[dmigwi.github.io/tapoo](https://dmigwi.github.io/tapoo/) : configure a model on the[agents\npage](https://dmigwi.github.io/tapoo/agents.html) , let it run, and download its log. Every prompt it receives is\npublished on the[prompts page](https://dmigwi.github.io/tapoo/prompts.html) .\n- **Tapoo Oracle** -[dmigwi.github.io/tapoo-oracle](https://dmigwi.github.io/tapoo-oracle/) : load a log and get its\nprofile against the Tapoo Agentic Behavior Rubric\n([source](https://github.com/dmigwi/tapoo-oracle) ).\n\nTapoo runs entirely in your browser, with no Tapoo server behind it. Logs stay on your device: what leaves it is the context each turn sends to the model endpoint you configure, and a credential goes only to the endpoint it was entered for.\n\nThe model is given a *navigation challenge*: find a target cell in a randomly generated maze. The maze has no cycles,\nexactly one success path that never changes once generated, and a variable number of dead-end branches. The model is\nnever handed the full maze layout at once: each turn describes only the neighbourhood around it, so any wider map is\none the model pieces together across turns. Alongside its current position, the target's position, the maze's\ndimensions and its traversal speed (below), each prediction request provides:\n\n- its cell visit history, capped to within a Manhattan distance of 4 (the `manhattanDistance` setting)\n- the outcome of its previous prediction\n- the open exits from its current cell to the connected neighbouring cells\n\nFrom that, it must derive its next moves: at least 1, with 2-4 suggested and no upper limit. Moves are applied in order until the first invalid one - a wall or out of bounds. There is no judge model and no self-reported success; every move is checked against the maze.\n\nThe open exits make the first move certain, while each one after it has to be deduced from context, and the odds of simply guessing right collapse - 33.33% for the second, 11.11% for the third, 3.70% for the fourth, and so on. The only way to improve those odds is to build a correct map of the surroundings from the context information available via the tool calls.\n\n**Playing safe** means submitting one move per turn - the only move the model can be certain of. It never needs to\nguess, so it never hits a wall. It also never covers more than one cell for the decay unit that turn costs, which\nleaves no margin for error.\n\n- The model starts with a budget of decay units equal to the number of cells in the maze. If the budget runs out before the target is located, the challenge is failed.\n- A dead-end branch usually gives itself away only at its end, and walking back out costs as much as walking in - so every branch explored spends units the route itself will still need.\n\nEach model is told its **traversal speed** - the new cells it was first to reach, divided by the decay units it was\ncharged - and what it says about its chances of finishing: below 1.0000x is a *backtracker*, exactly 1.0000x a\n*navigator*, and above 1.0000x a *trailblazer* - the class with the strongest margin for surviving its own mistakes.\n\nThe Oracle decomposes that rate into three factors: *route efficiency* (new cells per applied move), *batching*\n(applied moves per turn), and *accuracy* (turns per decay unit). Their product is the rate the counted turns give,\nwhich is why a report shows it as an approximation of the stated speed. Route efficiency and accuracy can only be\nlost, never gained, so batching is the one factor that can carry the rate above 1.0000x: a flawless single-move agent\ncannot pass it.\n\nSpeed is the rate view of a run. Quantifying survival, below, is the budget view of the same turns - and the batching\nfactor there is the same `b`, so the two decompositions share their middle term rather than competing.\n\nBatching forces every model to act on its own reading of an uncertain maze map. Some build an accurate picture and\nbatch confidently; some hallucinate walls or openings and act on them; some become so conservative they run out of\nbudget. [Tapoo Oracle]([https://dmigwi.github.io/tapoo-](https://dmigwi.github.io/tapoo-) oracle/) scores the exported log against a rubric of\ncapabilities and violations, kept separate rather than collapsed into a single scalar. A \"no\" means \"not observed in\nthis run\", not \"incapable\". Runs are stochastic and every maze is unique, so a profile is a pattern across many\nattempts, not a verdict from one run.\n\nEvery turn ends in exactly one state. The model chooses the moves, the maze decides which apply, and the charge follows from that outcome:\n\n| State | Condition | Charge | \n|---|---|---|\n| **progress** | all moves applied, at least one new cell entered | 1 decay unit | \n| **no progress** | all moves applied, no new cell entered | 1 decay unit | \n| **partial failure** | some moves applied, then one refused | 2 decay units | \n| **refusal** | the first submitted move was invalid | 2 decay units | \n| **empty** | no usable prediction replayed | 3 decay units | \n\nTwo consequences drive everything else. **A no-progress turn charges exactly what clean progress charges**, so\nstanding still is invisible to every other check: not a violation, no error debt, and it looks like success. And **a\nclean turn charges 1 decay unit however far it travels**, which is what makes batching valuable and retreating out of\na dead end affordable.\n\nOne charge, two opposite meanings. A no-progress turn is a **retreat** when every cell it entered reads `backtracking`\nor `explored` - legitimate, and required by the prompt once a dead end is confirmed - and an **oscillation** when a\ncell reads `oscillating`, which is a rubric violation. The budget cannot tell them apart; `visitStatus` can, and any\nrate that pools them reports a violation where there was compliance.\n\nThe split separates runs that a pooled rate would call identical. Of DeepSeek's 301 no-progress turns, 294 are oscillations and 7 retreats. The earlier level 1 loss is the mirror image: 59 retreats, not one oscillation - it lost while doing exactly what the prompt asks of it.\n\nSix figures, all read from one run's own log:\n\n| Symbol | Meaning | \n|---|---|\n| `A` | budget - decay units available, equal to the maze's cell count | \n| `D` | decay units actually charged | \n| `turns` | prediction cycles completed | \n| `moves` | applied moves - every replayed step that landed | \n| `p` | error debt - `D - turns` , what invalid moves and malformed responses cost | \n| `b` | batch depth - `moves / turns` | \n\nThree more are recomputed every turn:\n\n| Symbol | Meaning | \n|---|---|\n| `U` | unvisited route cells - success-path cells not yet entered; only ever decreases | \n| `u` | decay units left | \n| `dist` | tree distance - moves along the only route from the current cell to the target, including the retrace out of any dead end it stands in; never less than `U` | \n\nA run finishes exactly when the budget covers what it spent:\n\n```\nmoves / b  +  p  <=  A\n\nheadroom(b)  =  A - moves/b - p        decay units left when the run ends\n```\n\nHeadroom is not a property of the run alone: the same route and the same errors give a different figure at every batch\ndepth, so it means nothing quoted without its `b`. Subtracting `D` from `A` at the achieved depth splits it into three\nterms that each name a different cause:\n\n```\nheadroom  =  (A - moves)   +   (moves - turns)   -      p\n              route slack       batch credit       error debt\n```\n\n| Term | Measures | Sign | \n|---|---|---|\n| **route slack** | decay units for cells never walked - maze shape plus route-finding skill | either | \n| **batch credit** | decay units saved by covering several cells for one charge; zero at `b = 1` | `>= 0` | \n| **error debt** | decay units lost to invalid moves and malformed responses | `>= 0` | \n\n**A model survives its own mistakes when route slack plus batch credit covers its error debt.**\n\nSetting `headroom(b) = 0` gives the depth a run needed to survive what its route cost and its errors spent:\n\n```\nb_min  =  moves / (A - p)\n```\n\n| Run | moves | error debt | b required | b achieved | margin | \n|---|---|---|---|---|---|\n| GLM-5.3, level 54 | 615 | 117 | 1.273 | **1.723** | +0.450 | \n| Gemma4, level 54 | 602 | 9 | 1.019 | **1.246** | +0.227 | \n| Gemma4, level 1 | 68 | 0 | 0.971 | **1.015** | +0.044 | \n\nApplied moves are counted from the replay, including each run's deciding turn - which the log never reports directly, since a turn's outcome arrives with the next turn's tool calls and a winning turn has no successor. It is recovered by replaying that last prediction against the maze.\n\n`b_min < 1` means batching was never needed. That is true only of the level 1 run, whose 70-unit budget covered a\n69-move route. Both level 54 winners had to batch. Holding each run's route and errors fixed and sweeping `b`:\n\n```\n                route slack   batch credit   error debt   headroom\nGLM-5.3 L54         -15           258           117         +126   won\n  at b = 1          -15             0           117         -132   would have lost\n\nGemma4 L54           -2           119             9         +108   won\n  at b = 1           -2             0             9          -11   would have lost\n\nGemma4 L1             2             1             0           +3   won\n  at b = 1            2             0             0           +2   would still have won\n```\n\nGLM-5.3 spent 117 decay units on mistakes and earned 258 of batch credit that paid for them. Gemma4 at level 54 spent\n9 and still needed 119, because its route cost two units more than the maze has cells. Only at level 1, on a corridor\nwith no branches to explore, did a model finish without batching at all. That is the claim stated per run, in decay\nunits, and falsifiable: not \"batching is good\", but *this model's errors cost this much and its batching earned that\nmuch, so it survived by the difference*.\n\nRoute slack is negative on every level 54 run: each walked more steps than the maze has cells, because a dead end costs two steps per cell - one in, one out - and batching is what buys those steps back.\n\nBatching into new ground and batching a retreat are bounded by different things. Pooled across all 2,184 turns of the eight runs profiled so far, new cells entered per turn:\n\n```\nnew cells   0      1     2    3   4   >4\nturns     562   1409   189   21   3    0\n```\n\nThe first new cell is free - the current cell's `openMoves` names it. A second requires knowing the exits of a cell\nthe model has never stood in, and those are never stated; they can only be deduced. A visited neighbour's `openMoves`\nsays which walls that neighbour does *not* have, and the gaps narrow what the unvisited cell can be. Each further new\ncell pushes that elimination one cell deeper, and the only evidence for it is visited cells inside the history window\n\n- so the chain of certain moves cannot outrun the window's reach. At a Manhattan distance of 4 it runs out after about four layers, which is where the distribution stops.\n\nA retreat has no such bound: the window can hold 25 visited cells whose exits are already known, so Kimi K3 applied 7 moves in one turn to enter a single new cell.\n\nTwo constants follow, both observations with dates on them rather than properties of the game:\n\n| Constant | Value | Where it comes from | Raise it when | \n|---|---|---|---|\n| new cells one turn can break | `4` | the highest seen in 2,184 turns, and the window explains why | a run shows 5 | \n| fastest pace ever sustained | `1.52` | best 50-turn rolling average of new cells per turn, held by GLM-5.3 | a run sustains more | \n\nNeither is structural. The response schema sets `minItems: 1` with no maximum, so a longer batch is permitted, and a\nchain forced by boundary walls could in principle deduce a fifth new cell.\n\nSo a verdict must count **new route cells**, never distance travelled. At turn `t`:\n\n``` js\nU > 4u   =>   unwinnable\n```\n\n`U` falls by at most 4 per turn and `u` falls by at least 1, so `U/4 - u` can never decrease. **Once true, always\ntrue** - monotone by construction rather than by luck, and verified on every turn of all eight runs.\n\n| Run | fires | U at fire | decay left | Outcome | \n|---|---|---|---|---|\n| Apertus-v1.5-70B, level 1 | turn 34 of 41 | 54 | 13 | lost | \n| Gemma4, level 1 (earlier build) | turn 51 of 63 | 50 | 12 | lost | \n| all others | never | - | - | 4 won, 2 stopped | \n\nEverything that fires earlier is a warning, because none of it is monotone:\n\n| Signal | Claim | Fires: Apertus / earlier L1 / DeepSeek | \n|---|---|---|\n| `dist > u` | caution alone no longer suffices | 8 / 15 / 190 | \n| `U > 1.52u` | beyond the fastest new-cell pace ever sustained | 21 / 31 / 354 | \n| `dist > b*u` | beyond this run's own demonstrated pace | 19 / 19 / **105** | \n| `U > 4u` | beyond any new-cell pace ever observed | 34 / 51 / never | \n\nThe per-run pace fires earliest on DeepSeek, at turn 105 with 70% of its budget unspent, and flags no winner. It stays\na warning because `b` is a running mean that can rise.\n\nEight runs is an observation, not a threshold, and both losses were 70-cell corridor mazes with zero route slack while three of the wins were level 54 - maze shape is confounded with outcome. The verdict also needs the decoded maze, so it is available to a reader after the run, never to the model during it.\n\nEvery run behind the figures above. Each model name opens its live Oracle report; error debt is `D - turns` and decay\nleft is `A - D`, both exact from the log. The app version and maze are listed because the same model under a different\nbuild or maze area is a different experiment - three Gemma4 runs appear here across three versions. Rows are ordered\nby app version.\n\n| Model | App | Level (maze) | Turns | Error debt | Decay left | Outcome | \n|---|---|---|---|---|---|---|\n| [Gemma4](https://dmigwi.github.io/tapoo-oracle/r/AmdpdGxhYi5jb20vYXBpL3Y0L3Byb2plY3RzLzg2NDEzMTQyL3JlcG9zaXRvcnkvZmlsZXMvdGFwb28tdjIuNC44LWFnZW50LWFwaS1sb2dzLTE3ODc4MTkwOTcuanNvbi9yYXf4Ag) | v2.4.8 | 1 (10x7, 70) | 63 | 7 | 0 | lost | \n| [GLM-5.3](https://dmigwi.github.io/tapoo-oracle/r/AGRtaWd3aS8BEKq0c37Q6ioyFF3LwEpE_IwvcmF3LwEU-PPCJc3BJzZKGYIdg5IjL28KPHIvdGFwb28tdjIuNS4xLWFnZW50LWFwaS1sb2dzLTE3ODgwMjM1NDMtZ2xtLTUuMy5qc29uXK4) | v2.5.1 | 54 (25x24, 600) | 357 | 117 | 126 | completed | \n| [Gemma4](https://dmigwi.github.io/tapoo-oracle/r/AGRtaWd3aS8BEEpsa72wptbFAXQsth5o0CgvcmF3LwEUkAXQT98r6gDQrjuvqGY6mZ65G1svdGFwb28tdjIuNS4xLWFnZW50LWFwaS1sb2dzLTE3ODgwMjM1MTctZ2VtbWE0Lmpzb25PIg) | v2.5.1 | 54 (25x24, 600) | 483 | 9 | 108 | completed | \n| [GLM-5.1](https://dmigwi.github.io/tapoo-oracle/r/AGRtaWd3aS8BELChL-KeLPEI_vlaHAYDFTIvcmF3LwEUzxpghV6XeBTDjBYcF1Xvl4erHzEvdGFwb28tdjIuNS4xLWFnZW50LWFwaS1sb2dzLTE3ODgwNzEyNjgtZ2xtLTUuMS5qc29ud8Y) | v2.5.1 | 54 (25x24, 600) | 473 | 111 | 16 | completed | \n| [Kimi K3](https://dmigwi.github.io/tapoo-oracle/r/AGRtaWd3aS8BEMu4TYKMRX6FBQpIh8YyzdwvcmF3LwEU3D6C-jZrvLYCVJm9bbM4wxBQkAUvdGFwb28tdjIuNS4xLWFnZW50LWFwaS1sb2dzLTE3ODgwNzE1OTEta2ltaS1rMy5qc29uzdo) | v2.5.1 | 54 (25x24, 600) | 329 | 22 | 249 * | stopped - stalled 80 turns | \n| [DeepSeek v4 Pro](https://dmigwi.github.io/tapoo-oracle/r/AGRtaWd3aS8BEAwRLyf4RUq_ZIJa2M08ZrUvcmF3LwEUCyWgg1-xfxJKmZE5plyWUQDii4wvdGFwb28tdjIuNS4xLWFnZW50LWFwaS1sb2dzLTE3ODgwMjM1MjUtZGVlcHNlZWstdjQtcHJvLmpzb25YEw) | v2.5.1 | 54 (25x24, 600) | 379 | 16 | 205 * | stopped - oscillating | \n| [Gemma4](https://dmigwi.github.io/tapoo-oracle/r/AmdpdGxhYi5jb20vYXBpL3Y0L3Byb2plY3RzLzg2NDEzMTQyL3JlcG9zaXRvcnkvZmlsZXMvdGFwb28tdjIuNi4xLWFnZW50LWFwaS1sb2dzLTE3ODkyNDAzNTctZ2VtbWE0LWxldmVsMS5qc29uL3Jhd6cH) | v2.6.1 | 1 (10x7, 70) | 67 | 0 | 3 | completed | \n| [Apertus-v1.5-70B](https://dmigwi.github.io/tapoo-oracle/r/AmdpdGxhYi5jb20vYXBpL3Y0L3Byb2plY3RzLzg2NDEzMTQyL3JlcG9zaXRvcnkvZmlsZXMvdGFwb28tbG9ncy1zY2hlbWE1LjItdjIuNi4yLTE3ODk0MDg0MDE2OTUuanNvbi9yYXfPrw) | v2.6.2 | 1 (10x7, 70) | 41 | 29 | 0 | lost | \n\n* position at the halt; the run had not ended.\n\nThe error-debt column is where the framework earns its keep. DeepSeek and Kimi K3 carried debts of 16 and 22 decay units, lower than either GLM run, and neither finished; GLM-5.3 carried 117, the highest of any run, and finished first, because its batch credit of 187 more than covered them. What ended the two stalled runs was not mistakes but turns that bought no new ground. Every model that completed level 54 was still a backtracker; none reached 1.0000x.\n\nOnly the Apertus run carries an entries checksum, which exports gained in v2.6.2. The five level 54 logs (v2.5.1) and the two earlier level 1 runs (v2.4.8 and v2.6.1) predate it, so the Oracle verifies nothing on them.\n\nThe live site above is the quickest way in. Tapoo also runs locally, and ships a Go terminal build of the maze without agent profiling - profiling is browser-only.\n\n```\ngo install github.com/dmigwi/tapoo@latest\ntapoo\ngo run .\nmake frontend-install\nmake frontend-build\n```\n\nThen serve `public/` and open `/index.html`.\n\n```\nmake docker-build\nmake docker-run\n```\n\nThen open `http://localhost:5500/`.\n\n## **Gameplay And Controls**\n\n**Objective:** *Guide the blue player to the red destination before the score drops to zero.*\n\nTapoo increases maze area as levels rise. Progress continues until the current terminal window or browser viewport can no longer fit the next maze cleanly.\n\n- `Arrow keys` : move the player\n- `Ctrl+B` : cycle maze wall weight\n- `Space` or`Esc` : pause the current run\n- `Enter` : proceed after pause, win, or failure\n- `Ctrl+C` : quit\n\n- Keyboard controls mirror the terminal controls\n- `Ctrl+Alt+R` : reset browser progress\n- On touch devices, on-screen controls are shown automatically\n\n## **Highlights**\n\n- AI model behaviour profiling under structured uncertainty, against Ollama, OpenAI-compatible, and Anthropic APIs, with up to 5 agent seats\n- Capability and violation profiles through the companion [Tapoo Oracle](https://github.com/dmigwi/tapoo-oracle) application\n- Browser SPA with a black-and-green terminal feel, plus a Go terminal build of the maze\n- Adjustable wall weights with live cycling during play\n- Per-level scoring and progression\n- Pause, resume, retry, and next-level flow\n- Best-effort persistence for terminal and browser sessions\n- Manual GitHub Pages deployment for the web build\n- Go and TypeScript test coverage in CI\n\n## **Browser App**\n\nThe browser build emits versioned JS/CSS bundles under `public/js` and `public/css`, then serves the SPA from\n`public/index.html`. These are build output and are not committed.\n\nThis compiles [frontend/tapoo.ts](https://github.com/dmigwi/tapoo/blob/master/frontend/tapoo.ts) with `esbuild` into a minified browser bundle.\n\nAvailable pages:\n\n- `/index.html` for the game\n- `/agents.html` for configuring and running HTTP-driven AI agents\n- `/prompts.html` for previewing the exact prompts and tool definitions sent to an agent\n- `/privacy.html` for the browser storage and agent data privacy notice\n\nThe project-level [Dockerfile](https://github.com/dmigwi/tapoo/blob/master/Dockerfile) builds the browser frontend in a Node/pnpm builder stage, then copies the\ngenerated [public](https://github.com/dmigwi/tapoo/blob/master/public) output into an nginx runtime image. The container serves static files only; Go terminal\ngameplay is not part of the runtime image. If Docker Desktop is not desired,\n[Colima](https://github.com/abiosoft/colima) can provide a lightweight local Docker-compatible runtime for building\nand running the same image.\n\n```\nmake docker-build            # build the tapoo image\nmake docker-run              # serve it on http://localhost:5500\nmake docker-shell            # open a shell in the Docker build image\n```\n\nDirect Docker equivalents:\n\n```\ndocker build -t tapoo .\ndocker run --rm -it -p 5500:80 tapoo\n```\n\n## **AI Agents**\n\nInstead of (or alongside) a human player, up to 5 agent seats can each be configured to play the maze by calling an HTTP chat-completions endpoint every turn.\n\n- **Ollama** - native`/api/chat` shape\n- **OpenAI-compatible** -`/v1/chat/completions` (also covers self-hosted servers such as vLLM, LM Studio, and\nllama.cpp, and routers such as Hugging Face's Inference Providers)\n- **Anthropic** -`/v1/messages`\n\nEach seat is configured independently from the `/agents.html` overlay:\n\n- player name, model, endpoint, and API provider\n- credential (bearer token or API key) and custom extra headers, e.g. `anthropic-version`\n- **reasoning effort** - how hard the model reasons before replying; the available levels and default depend on the\nprovider, since reasoning support varies by model (e.g. Kimi K3 handles heavy reasoning well, Gemma 4 does not)\n- **echo back reasoning** - whether prior reasoning content is replayed on the next request, off by default since\nguidance on this conflicts across reasoning models; locked off automatically whenever reasoning effort is set to`none` , and has no effect for Anthropic agents\n\nThe `/prompts.html` page mirrors the exact system prompt, tool definitions, and required response format an agent\nreceives, so its behavior can be inspected without capturing live traffic.\n\nTapoo produces downloadable `agent-api` gameplay logs. [Tapoo Oracle](https://github.com/dmigwi/tapoo-oracle) owns the\nlog contract, behavior rubric, and analysis engine that turn those exports into capability and violation profiles.\nOracle is included in this repository as the [`tapoo-oracle`](https://github.com/dmigwi/tapoo/blob/master/tapoo-oracle) git submodule and can be initialized\nwith:\n\n```\ngit submodule update --init --recursive\n```\n\n## **Persistence**\n\nTapoo carries a semantic version (`MAJOR.MINOR.PATCH`), shown in the terminal intro banner and in the browser footer.\nBrowser storage additionally carries its own separate schema version, independent of the app version above - see the\nbrowser storage note below.\n\nThe terminal version stores best-effort runtime state in a local file:\n\n- `.tapoo.store`\n\nIt keeps track of:\n\n- current level\n- selected wall weight\n- last game progress state\n\nIf the persisted state cannot be read or validated, Tapoo falls back to default startup behavior.\n\nThe SPA stores gameplay state in browser storage:\n\n- `localStorage` for durable preferences such as level and wall weight, and for configured agent seats (including\ncredentials, endpoints, and per-agent reasoning settings)\n- `sessionStorage` for the active round snapshot, per-tab agent session metrics, and the tab-session ID used to scope\nTapoo Logs\n- `IndexedDB` for Tapoo Logs when available; logs remain on the current device and are scoped to the current tab\nsession for download/reset\n\nEvery stored entry is tagged with the current storage schema version. On startup, Tapoo detects entries left over from an older schema version and asks for acknowledgement before removing them rather than attempting to migrate them.\n\nPrivacy note: browser storage stays on the current device unless the user clears it, resets progress, removes configured agent data, or downloads/shares Tapoo Logs. Browser storage is lightly obfuscated to discourage casual tampering, but it should not be treated as strong encryption for personal data. When AI Agent play is configured, gameplay context such as player name, current cell, destination cell, submitted moves, score, level, and traversal history may be sent to the configured agent API endpoint. If IndexedDB is unavailable, Tapoo falls back to smaller sessionStorage logs and may limit higher AI Agent levels.\n\nThe deployed browser pages include a short privacy notice at `privacy.html`.\n\n## **Development**\n\n- Go `1.25+`\n- pnpm `11.25.0`\n- Node.js `24` LTS\n- `golangci-lint v2.12.2`\n\n```\nmake help\nmake frontend-install\nmake frontend-quality\nmake frontend-build\nmake test\nmake ci\nmake docker-build\nmake docker-run\n```\n\nGo and TypeScript each carve mazes with their own generator, so [parity-harness/bench-report.mjs](/parity-\nharness/bench-report.mjs) runs both ports' benchmark suites ([maze/bench](https://github.com/dmigwi/tapoo/blob/master/maze/bench) and\n[frontend/bench](https://github.com/dmigwi/tapoo/blob/master/frontend/bench)) from one shared PRNG seed and checks that the two generators produce identical per-\nsample maze structures rather than merely eyeballing the numbers. A flagged case means a reproducible behavioral gap\nbetween the ports, not just run-to-run noise.\n\n```\nmake go-bench        # Go maze generation only\nmake frontend-bench  # TypeScript maze generation only\nmake ci-bench        # both, with the cross-port parity check\n```\n\nEach run also writes `parity-harness/bench-report.json` with the full comparison and SVG charts.\n\n## **Contributing**\n\nContributions are welcome, but contributors should install the repository pre-commit hook before creating commits.\n\n1. Install the required toolchains:\n`Go 1.25+` ,`Node.js 24 LTS` ,`pnpm 11.25.0` , and`golangci-lint v2.12.2`\n2. Install frontend dependencies:\n\n```\nmake frontend-install\n```\n\n1. Install the repository git hooks:\n\n```\n./scripts/install-hooks.sh\n```\n\nThe hook installer copies [scripts/hooks/pre-commit](https://github.com/dmigwi/tapoo/blob/master/scripts/hooks/pre-commit) into `.git/hooks/pre-commit`.\n\nThe pre-commit hook runs:\n\n```\ngolangci-lint run\n```\n\nThis is required so commits are checked locally before they are pushed. If `golangci-lint` is not installed, the hook\ninstallation script will warn you and show installation options.\n\n```\nmake ci\n```\n\nAt minimum, contributors should make sure:\n\n- Go tests pass\n- frontend typecheck, lint, and tests pass\n- `golangci-lint run` passes\n- `govulncheck` passes\n\n- `make lint` : run`golangci-lint`\n- `make govulncheck` : run`govulncheck`\n- `make frontend-quality` : run frontend typecheck, lint, and tests\n- `make frontend-build` : build the minified SPA bundle\n- `make test` : run frontend checks plus Go race tests with coverage\n- `make ci` : run the local equivalent of the main CI pipeline\n\n## **CI And Deployment**\n\nThe main CI workflow lives at [`.github/workflows/go.yml`](https://github.com/dmigwi/tapoo/blob/master/.github/workflows/go.yml) and runs:\n\n- Go linting\n- `govulncheck`\n- frontend typecheck, tests with coverage, and build\n- Go race tests with coverage\n- maze benchmarks with the cross-port parity check, when maze generation changes\n- coverage uploads for Go and frontend reports\n\nThe Pages workflow lives at [`.github/workflows/pages.yml`](https://github.com/dmigwi/tapoo/blob/master/.github/workflows/pages.yml).\n\nPages deployment is manual-only.\n\nTo deploy:\n\n1. Open the repository on GitHub.\n2. Go to `Actions` .\n3. Choose `Deploy Pages Manually` .\n4. Click `Run workflow` .\n5. Select the branch you want to deploy.\n\nImportant:\n\n- GitHub Pages should be configured to use `GitHub Actions` as the publishing source.\n- Since the workflow is manual, it deploys the branch selected at run time.\n\n```\nmaze/          Go gameplay, rendering, persistence, and tests\nfrontend/app/  TypeScript SPA logic and tests\npublic/        Static site assets, HTML, CSS, images, and built JS\nscripts/       Frontend build and hook helpers\ntapoo-oracle/  Companion agent-log analyzer (git submodule)\n```\n\nThis project is licensed under the Apache License 2.0. See [LICENSE](https://github.com/dmigwi/tapoo/blob/master/LICENSE). Tapoo is distributed on an `AS IS`\nbasis, without warranties or guaranteed support.", "url": "https://wpnews.pro/news/can-your-ai-model-survive-its-own-mistakes", "canonical_source": "https://github.com/dmigwi/tapoo", "published_at": "2026-09-24 13:13:39+00:00", "updated_at": "2026-09-24 13:30:37.903365+00:00", "lang": "en", "topics": ["ai-safety", "ai-agents", "ai-research", "ai-tools"], "entities": ["Tapoo", "Tapoo Oracle", "Tapoo Agentic Behavior Rubric", "dmigwi"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/can-your-ai-model-survive-its-own-mistakes", "markdown": "https://wpnews.pro/news/can-your-ai-model-survive-its-own-mistakes.md", "text": "https://wpnews.pro/news/can-your-ai-model-survive-its-own-mistakes.txt", "jsonld": "https://wpnews.pro/news/can-your-ai-model-survive-its-own-mistakes.jsonld"}}