ReasonTree · every number and quote below comes from a captured, archived run

Why give a language model a tree?

When you ask an AI model a hard question, it answers the way it was built to: one word at a time, in a single unbroken stream. Researchers call this autoregressive generation, and the "let me think step by step" text you sometimes see is called a chain of thought. It looks like reasoning, and often it works. But notice what the model can't do in that stream: it can't lay two ideas side by side. It can't put an idea down, try another, and come back. And it has no scratchpad other than its own words — so when a puzzle needs it to track a changing situation precisely, the words drift, and the model starts believing things about the situation that are no longer true. Once that happens, more thinking doesn't help. It just produces a longer, more confident version of being lost.

ReasonTree is a small open-source controller built around a different picture. Instead of one long monologue, the problem becomes a tree: the current situation is the trunk, each candidate idea is a branch, and every branch is played out on a real copy of the situation — in software terms, a state that actually updates, not a description of one. For each branch, something pushes back: an opponent's best counter-move, a failing test, a counter-example. Branches get scores, weak ones are pruned, and a strict budget of time and compute (bounded search) decides when to stop. Wherever a claim can be checked mechanically, a verifier — real executed code, not another opinion — gets the final word. Only then does the language model speak: one short call to explain the branch that survived.

Below are four real, captured experiments — a chess puzzle, a probability question, a debugging session, and a business decision. Each one exercises a different part of the tree, so along the way you'll see which specific feature earns its keep: executable states, verifiers, scoring, or the adversarial pushback. At the end, we place ReasonTree honestly among its research ancestors — Tree of Thoughts, Monte Carlo Tree Search, and friends — including a small head-to-head we ran for this page.

Case 1 · strategy under pressure

A chess puzzle, watched from the inside

ReasonTree features at workexecutable stateadversarial replybounded budget

First, what is this task? A chess tactics puzzle is a position from a real game where exactly one move wins decisively — every alternative lets the opponent escape. Puzzle sites rate them by how often humans solve them; this one is rated 1809, roughly "strong club player" territory. There is nothing to debate and nothing to interpret: a move either works against the opponent's best defense or it doesn't, which is exactly why we use chess as the microscope. Nobody can argue with the scoreboard.

Now think about what answering this requires from a model that can only write words. To evaluate one candidate move it must imagine the move, imagine the opponent's best answer, imagine its own follow-up — while keeping all thirty-two pieces straight, in prose, across every line it explores. Each imagined move changes the position; each new candidate means rewinding to the original position from memory. The captured stream in the first panel shows what that does in practice. Haiku starts out impressively organized — it reads the position correctly and lists ideas. Then the drift begins: it circles back to the same candidate a third time, "double-checks" the board and misremembers it ("wait — the king can't be on g7 if there's a pawn there" — it could, there wasn't), and at 127 seconds it commits, politely and confidently, to a move that is not merely wrong but illegal — its own knight is standing on the path. No time limit was in play; we let it run as long as it wanted.

The second panel is the same model inside ReasonTree, and the difference is not effort — it's plumbing. The controller never remembers the board; it computes it. Every legal move is enumerated by code, each one is played on a real copy of the position, and for each, the opponent answers with its best move — what game programmers call an adversarial search (four levels deep here; the classic negamax algorithm, for the technically curious). Positions are scored by checkmate and material, a 12-second budget caps the work, and the winning branch — Qxd5, a queen sacrifice — surfaces in about four seconds. Click any branch below: the counter-moves it had to survive are all there.

On the full frozen 25-puzzle benchmark this is not a one-off: raw Haiku solved 1 of 25 under a 30-second operational cap; the tree solved 21 of 25. And the pattern survives a model tier. We repeated the entire protocol with Claude Sonnet 5 — a far stronger model — on a new frozen holdout of harder puzzles (rated 2200–2300, master-level) with an eight-times-longer budget: raw Sonnet solved 3 of 25 in a median of 57 seconds; the unchanged adapter solved 18 of 25 in a median of three, and the first ten rescue cases ran end-to-end with Sonnet as the explanation layer at 10/10, about $0.008 per case. One more honest wrinkle from that run: searching deeper (depth 5 and 6) scored worse than the frozen depth-4 config — a classic horizon effect — a reminder that bounded and even beats big and truncated. The lesson travels beyond chess: whenever a problem has precise rules and a changing state — a spreadsheet, a database, a codebase, a schedule — "what happens if" can be computed instead of imagined.

raw Haiku — thinking out loud, no tree, no capscommitted to the wrong move at 127.44s
wall 127.44s17594 chars streamed12974 output tokens$0.0692
t = 1.9s

Let me analyze this chess position. I need to find the single best move for White. FEN: 2r2rk1/4q1p1/p3p2p/1p1b4/P7/1QN1RP2/1P3P1P/2R3K1 w - - 0 23 Let me understand the board: ``` 8: . . r . . r k . (rank 8) 7: . . . . q . p . (rank 7) 6: p . . . p . . p (rank 6) 5: . p . b . . . . (rank 5) 4: P . . . . . . . (


t = 30s — the benchmark's 30-second cap — nothing usable committed yet
t = 58.1s

Hmm, so Ne4 doesn't seem to trap the queen or win material immediately. Let me think about whether Ne4 improves White's position in some other way. After 1. Ne4, the knight is centralized and attacks the queen. The queen moves, and then what? I'm not sure this leads anywhere concrete. Let me go ba

t = 59.0s

Let me go back to considering Rxc8+. That seems like the most forcing move. After 1. Rxc8+ Qxc8, White has traded rooks. The position is roughly equal in material. But I should evaluate the resulting position more carefully. Is White better, worse, or equal?

t = 90.4s

But wait—the king can't be on g7 if there's a pawn there. Let me recheck the pawn structure from the position. Looking at rank 7: e7 has the queen, g7 has a pawn. So the king must move elsewhere after the rook check. The available squares are Kf7, Kh7, or Kh8. In each case, White follows with Rc7,

t = 93.2s

Let me examine whether there's a stronger initial move I've overlooked. The position warrants a closer look at other candidate moves before committing to the rook capture. What about Qxd5+? The queen takes the bishop with check, which forces the king to respond and wins material

t = 123.7s

So the move is c1c8 in UCI notation. Let me verify the board position once more to make sure I have the right setup before finalizing this answer. Looking at the full board: the black rook sits on c8 and black king on g8. The white rook is actually on e3, not c1 as I initially thought. Checking rank 1, there's a rook on c1 and the white


t = 127.44s — finally commits to c1c8 (Rxc8+) — wrong (expected b3d5 (Qxd5!)) — c1c8 is not even legal: White's own knight on c3 blocks the c-file
ReasonTree bounded searchevery branch inspectable
FEN: 2r2rk1/4q1p1/p3p2p/1p1b4/P7/1QN1RP2/1P3P1P/2R3K1 w - - 0 23
depth: 4max nodes: 300000timeout s: 12.0nodes used: 137444wall seconds: 4.4327completed full root: True
White to movestate
  • Qxd5candidateselected+1.6
    Qxd5 comes out ahead by 2.3 pawns once the line settles
    line: Qxd5 exd5 Rxe7 bxa4
    • exd5replysurvives+1.6
      opponent's candidate resistance, scored from our side
      line: exd5 Rxe7 bxa4
      • Rxe7 bxa4continuation
        our follow-up on this reply's principal variation
    • Rce8replysurvives+3.0
      opponent's candidate resistance, scored from our side
      line: Rce8 Qh5 bxa4
      • Qh5 bxa4continuation
        our follow-up on this reply's principal variation
    • Rfe8replysurvives+3.0
      opponent's candidate resistance, scored from our side
      line: Rfe8 Qe4 bxa4
      • Qe4 bxa4continuation
        our follow-up on this reply's principal variation
    • Ba8replysurvives+0.9
      opponent's candidate resistance, scored from our side
      line: Ba8 axb5 axb5
      • axb5 axb5continuation
        our follow-up on this reply's principal variation
    • Bb7replysurvives+0.9
      opponent's candidate resistance, scored from our side
      line: Bb7 axb5 axb5
      • axb5 axb5continuation
        our follow-up on this reply's principal variation
    • Bc4replysurvives+0.9
      opponent's candidate resistance, scored from our side
      line: Bc4 axb5 axb5
      • axb5 axb5continuation
        our follow-up on this reply's principal variation
    • Bxf3replyrefuted-1.3
      opponent's candidate resistance, scored from our side
      line: Bxf3 b4 bxa4
      • b4 bxa4continuation
        our follow-up on this reply's principal variation
    • Qg5+replysurvives-0.3
      opponent's candidate resistance, scored from our side
      line: Qg5+ Kf1 b4
      • Kf1 b4continuation
        our follow-up on this reply's principal variation
    • Ba8replysurvives-0.2
      opponent's candidate resistance, scored from our side
      line: Ba8 h4 Qxh4
      • h4 Qxh4continuation
        our follow-up on this reply's principal variation
  • Nxd5candidaterefuted-2.0
    the opponent's best reply keeps this branch 1.7 pawns worse
    line: Nxd5 Rxc1+ Kg2 Qg5+
  • Qa3candidaterefuted-2.0
    the opponent's best reply keeps this branch 1.7 pawns worse
    line: Qa3 b4 Nxd5 Rxc1+
selected pathsurviving branchrefuted branchclick a node to open its counter-branches
Controller selection: Qxd5 — the branch that survives the opponent’s strongest reply within the budget.
Case 2 · everyday statistics

Two alarms, one email — how sure are we, exactly?

ReasonTree features at workverifier computes what's knowablerefusing false precision (the gap rule)branching makes assumptions visible

No chessboard here — this is the kind of question that lands in a Slack channel. A company's mail system sees about 1 phishing message per 100. It runs two phishing scanners. Each scanner, measured on its own, catches 90% of phishing emails and false-alarms on 5% of legitimate ones. This morning, both scanners flagged the same message, and the security lead asks the natural question: "Okay — what's the probability this one is actually phishing?" To be precise about what's being asked: of all the messages that ever get double-flagged, what fraction are truly phishing? Statisticians call this the posterior probability; everyone else calls it "how sure are we."

There is a textbook way to compute it, and it's genuinely tempting. Phishing is rare (1 in 100), so even a good scanner cries wolf a lot — that's the famous base-rate trap. But two independent alarms fix that: the odds that two unrelated scanners both false-alarm on the same innocent email are tiny (5% of 5%). Run the arithmetic — Bayes' theorem — and out comes a satisfying 76.6%. One catch. That word independent. These two scanners come from the same vendor and share code and training data. They are two witnesses who went to the same school and read the same books: when one is fooled, the other tends to be fooled by the very same trick. How much does their agreement really add, then? Here is the uncomfortable truth: the numbers given do not say. Nobody has measured how often the two scanners fail together, and no amount of cleverness can conjure that missing measurement out of thin air.

Watch what the raw model does with this. Midway through its thinking, it spots the trap — genuinely, in its own words:

raw haiku, thinking out loud · t = 21.0s its instinct was right…
Without knowing the correlation between the scanners, I can't give a precise answer. The 76.6% figure assumes independence, which is likely too optimistic given they share code and training data. The true probability probably falls between 15.4% (perfect correlation) and 76.6%, closer to the lower end. I should acknowledge this …
raw haiku, final answer · t = 47.43s …and it caved anyway
77% Justification: Using Bayes' theorem: P(phishing | both flag) = (0.9² × 0.01) / (0.9² × 0.01 + 0.05² × 0.99) = 0.0081 / 0.010575 ≈ 77%. Critical limitation: This assumes the scanner errors are independent. Since both scanners share code and training data, their errors are positively correlated—if one makes a false positive, the other likely will too. This correlation means the true probability is lower than 77%. Without m …

The question demanded one number, so it delivered one: 77% — the textbook figure that silently assumes the two scanners fail independently, the very assumption it had just doubted. It even guessed a direction ("the true probability is lower"), which the facts don't support either. Cost of the confident answer: 47.43s, 4407 tokens, $0.0264. This is the single-stream weakness in its purest form: noticing a flaw is possible, but nothing in the stream forces the flaw to change the answer.

ReasonTree's structure changes who is allowed to have the last word. "Assume independence and multiply" isn't the method here — it's just one branch, sitting next to a rival branch that asks: what do the stated facts actually pin down? That second branch goes to a verifier — a small piece of exact mathematics (bounds under unknown dependence, for the technical reader) that computes every probability consistent with the given facts. The answer it returns is not a number. It's a range, and the range is enormous:

13.9%every value in this range fits the given facts100%
↑ 76.6% — the tempting "textbook" number is just one unproven point

Both ends of that range are real possibilities, and each has a plain-English story. The bottom (13.9%): if the scanners' mistakes overlap almost completely, the second flag adds nearly nothing — you effectively have one scanner wearing two badges, and one flag on a rare event mostly means "false alarm." The top (100%): if their false alarms happen never to coincide, then a double flag is practically proof. Between those extremes, any value fits the facts. So the only honest answer to "give me the exact probability" is: underdetermined — you cannot know from this data, and here is precisely the measurement that would settle it (how often do both scanners flag the same legitimate email?). ReasonTree calls this the gap rule: when two fact-compatible worlds disagree, name the gap instead of picking a world. That refusal is a feature. A wrong-but-confident 77% could justify auto-deleting customer email; "between 14% and 100%, and here's what to measure" leads somewhere useful.

ReasonTree bounded searchevery branch inspectable
verifier: exact bound computationwall seconds: 14.8model calls: 1
Both scanners flagged itstate
  • Trust the textbook mathbranchrefuted
    Bayes' theorem with independent errors gives 76.6% — but independence is an assumption, not a fact. These scanners share code and training data.
  • Ask what the facts actually pin downbranchselected
    A dependence-bounds verifier computes every probability consistent with the stated facts: anywhere from 13.9% to 100%. One exact number is mathematically unknowable from this data.
    • name the missing measurementcontinuation
      How often do both scanners flag the same legitimate email? Measure that, and the range collapses to a real answer.
selected pathsurviving branchrefuted branchclick a node to open its counter-branches
Controller selection: report the honest range, name the missing fact — the branch that survived the pushback, and it tells you which measurement would settle the question.
reasontree-check + haiku, final answer · 14.8s verified
- Status: Underdetermined. - Verified range: 13.9% to 100%. - Independence scenario: 76.6%, explicitly labeled unproven. - Missing measurement: joint error rates between the two scanners.

Three times faster than the raw attempt, and — more importantly — it refuses the false precision and names the fact that would close the question. The same trap, by the way, is everywhere once you see it: two medical tests processed by the same lab, two references who heard the story from the same person, two AI models trained on the same data, two auditors using the same checklist. Agreement feels like confirmation; without independence, it's often just an echo.

Case 3 · debugging

The bug that wasn't where it looked

ReasonTree features at workhypotheses as branchesverifier executes the codefix verified, not recommended

A Python service ships a small feature: every user can set their own request timeout. One day a customer sets theirs to 60 seconds — and suddenly every user's timeout is 60. Settings are leaking across users who have never touched them. Here's the entire relevant code:

import functools @functools.lru_cache() def get_config(env, overrides={}): config = {"retries": 3, "timeout": 10} config.update(overrides) return config def apply_user_settings(user_prefs): cfg = get_config("prod") cfg["timeout"] = user_prefs.get("timeout", cfg["timeout"]) return cfg

Two things in this snippet deserve a plain-language introduction. @functools.lru_cache() is Python's "remember the answer" sticker: the first time get_config("prod") runs, the result is stored; every later call skips the work and returns the stored result. Useful — but note the subtlety: it remembers the object itself, not a photocopy. Every caller receives the same dictionary. The second thing is overrides={} — a mutable default argument, one of Python's most famous gotchas, the thing every code reviewer has been trained to pounce on the moment they see it. It looks guilty. That's precisely what makes this case interesting: there's a well-known suspect standing right next to the actual culprit.

Credit where due: asked raw, Haiku correctly blamed the cache this time (19.64s, 1758 tokens, $0.0133). But look at what that answer is: a plausible story about code it never ran. You'd still have to verify it yourself before shipping the fix — and if it had picked the decoy instead, the answer would have read exactly as confident.

ReasonTree treats a debugging session as hypothesis testing. Each suspect becomes a branch, and the verifier executes the actual program. Branch one — "the cache hands out one shared dict" — is confirmed by reproduction: run the code, watch user 2 inherit user 1's timeout, observe that get_config("prod") really does return the identical object twice. Branch two — the famous decoy — is cleared by direct observation: after the failure, the default dict is still empty; it was never touched. Then the fix branch: apply copy-on-return, re-run the same scenario, watch the symptom disappear. The fix isn't recommended; it's demonstrated. All of the code execution took under a millisecond; one short model call writes it up. Total: 7.32s and $0.007 — roughly half the time and cost of the raw attempt, with proof attached instead of plausibility.

The pattern generalizes to most "how is this even possible?" bugs: settings that leak between users, tests that pass alone and fail together, caches that serve stale data, "works on my machine." Wherever a hypothesis can be turned into a few lines of executable check, the tree turns detective stories into experiments.

ReasonTree bounded searchevery branch inspectable
code executions: 3verifier wall: under 1 msexplain call wall seconds: 7.32total cost: $0.0070
User 2 inherits user 1's timeoutstate
  • lru_cache hands out ONE shared dicthypothesisselected
    Executed: get_config('prod') is get_config('prod') → True. After user 1 sets 60, user 2 reads 60. Symptom reproduced on the real code.
    • fix: return a copycontinuationsurvives
      Re-ran the same scenario with dict(...) copy-on-return: user 2 reads 10 again. Symptom gone — the fix is verified, not assumed.
  • the suspicious overrides={} defaulthypothesisrefuted
    Executed: after the failure, the default dict is still {} — it was never mutated. A classic decoy that looks guilty and isn't.
selected pathsurviving branchrefuted branchclick a node to open its counter-branches
Controller selection: shared cached dict — fix by returning a copy — confirmed by executing the real code; the decoy was cleared the same way.
the tree's explanation layer (haiku), given the executed evidence every sentence backed by a run
Root cause (verified): `functools.lru_cache` returns the same mutable dict object across calls, and `apply_user_settings` mutates it in place, causing user2 to see user1's timeout value. Why Branch B is refuted: The mutable default argument `overrides={}` was never mutated, as directly observed in the execution evidence. Minimal fix: Return a copy of the cached dict from the cached function so each caller gets an independent mutable object: `return dict(get_settings())` or `return copy.copy(cached_result)`.
Case 4 · decision making

Ship the fix now, or wait a week?

ReasonTree features at workparallel advocate branchesadversarial skeptic passassumptions labeled, not hidden

Our last case has no verifier at all — no chess engine, no formula, no test suite can tell you the right answer. That's deliberate: most real decisions live here, and it's important to see what a reasoning tree can and cannot honestly do in this territory.

The setup: you advise a six-person B2B software startup with 40 customers. A bug is corrupting non-English characters (ç, ö, 漢字…) in the data-export feature; two customers are affected. Option A: a hotfix can ship tomorrow — but deploying it means disabling every customer's data export for up to 24 hours, starting tomorrow morning. Option B: wait for next week's scheduled maintenance window and fix it with zero downtime. Sounds like a judgment call between speed and disruption — until you read the account notes: one of the two affected customers is mid contract-renewal, worth 30% of the company's revenue, and their procurement team runs a data-export compliance test tomorrow afternoon as part of the renewal checklist. Now look again. Option A knocks out the very feature that customer will be testing, during the very hours they'll be testing it:

Tomorrow
Option A: all-customer export offline — "up to 24 hours"
⚠ renewal compliance test
6am10am2pm6pm10pm
The collision: the renewal customer tests data export while Option A has data export switched off.

To raw Haiku's credit, this time the single stream caught it — its very first step was to call the customer and move the test out of the deployment window:

raw haiku, final answer (excerpt) · 28.9s · $0.0163 spotted the collision — this time
Call the renewal customer today — Inform them directly of the bug, tomorrow's maintenance window, and estimated restoration time (underpromise). Ask if they can run their compliance test before 7am or after the estimated restore time, and offer to have an engineer standing by during their test. This removes ambiguity and gives them ownership of the solution path. 2. Test the hotfix tonight end-to-end — Validate the fix …

A genuinely good answer. But hold it next to Case 2 for a moment: the same model, on the same day, noticed the independence trap and still answered "77%." A single stream may catch the buried fact. Nothing makes it. Whether the collision surfaces depends on where the stream happens to wander — and you only get one stream.

The tree makes the catch structural instead of lucky. Two advocate branches each argue one option as hard as they can — and are required to list the biggest risks of their own plan against every stated fact. Then a skeptic pass cross-examines both branches, specifically hunting for facts that break them. In the captured run it found both of the things that matter. Against Option B, the fatal one:

the skeptic node, cross-examining option B branch refuted by a stated fact
If the test is tomorrow afternoon and the fix isn't deployed until next week, the customer will encounter the bug during their renewal compliance test. This is not a negotiable reschedule—it's a compliance checklist for a renewal decision. The bug discovery at that moment guarantees escalation and exactly the "forced into Option A under duress" scenario Branch B warns against. Waiting doesn't avoid the crisis; it defers it to the worst possible time. …

And against Option A — subtler and easy to miss — the skeptic caught the plan contradicting its own numbers:

the skeptic node, cross-examining option A hidden assumption exposed
A deployment that starts "tomorrow morning" and runs "up to 24 hours" does not have an afternoon window available for the test. The 4–6 hour estimate contradicts the stated "up to 24 hours" requirement. Branch A cannot have it both ways—either deployment finishes by afternoon (contradicting the stated scope), or export is still down during the test. …

The final recommendation (153.43s, $0.0928): hotfix tomorrow, but only sequenced around the test — call the customer first, verify the test can move, stage the deploy accordingly. Crucially, the answer ships with a table of its own assumptions ("the test is movable on 12-hour notice") and unverifiable facts, each labeled. Because no verifier exists for decisions, ReasonTree doesn't pretend one does: the output is marked unverified — an honest judgment, stress-tested, with its load-bearing assumptions in plain view. That's the most a reasoning system can truthfully offer here, and it costs about 6× the raw call — worth it when 30% of revenue rides on a scheduling detail, overkill for picking lunch.

ReasonTree bounded searchevery branch inspectable
branches: 2skeptic pass: 1wall seconds: 153.43total cost: $0.0928
Ship now or wait a week?state
  • Option A: hotfix tomorrowbranchselected
    Survives cross-examination — but only after the skeptic exposed its hidden assumption: the plan works only if the customer's test can actually move, which nobody has verified.
    • skeptic: your own numbers collidechallenge
      “Up to 24 hours” starting tomorrow morning does not leave an afternoon window. Call the customer first; treat the test time as an assumption, not a fact.
  • Option B: wait for next weekbranchrefuted
    The renewal customer runs its compliance test on the broken export tomorrow afternoon. Waiting doesn't avoid the crisis; it schedules the bug's discovery for the worst possible moment.
selected pathsurviving branchrefuted branchclick a node to open its counter-branches
Controller selection: hotfix tomorrow — but only sequenced around the compliance test — a judgment call, so it ships with its assumptions labeled instead of a proof.

The shape to remember: any decision where dated facts can collide. A kitchen renovation scheduled just before a family event; switching payroll vendors the month of a tax deadline; accepting a job offer whose start date quietly overlaps a signed obligation. One stream may notice. A tree with a skeptic pass must check.

The honest fine print

Where this doesn't help

If the model already verifies its work, the tree mostly adds cost. In our matched-compute experiments on math benchmarks (AIME) with tools enabled, one-shot agents wrote their own checking code and nearly saturated the test — extra tree structure gained nothing. We publish that result alongside the wins.

"Think in branches" as a mere prompt does nothing. We tested it: telling the model to build a tree in words, even with all legal moves listed, still failed the chess puzzles. The gain appears only when branches become executable — real states, real checks. Structure has to be in the machinery, not the phrasing.

Judgment calls get scrutiny, not proofs. Case 4 shows the ceiling: without a verifier, the tree can force hidden facts into view and label assumptions, but it cannot certify the decision — and says so.

Standing on shoulders

How this relates to Tree of Thoughts, MCTS, and friends

None of the individual ideas here are new, and it matters to say so plainly. Researchers have been giving language models more structure for years, and ReasonTree borrows from most of them:

Chain of Thought2022

Ask the model to think out loud before answering. The baseline everything else builds on.

Shared: nothing structural — this is the single stream all four cases start from.

Self-Consistency2022

Ask the same question many times, take the majority answer. Wisdom of a crowd of one model.

Difference: votes measure agreement, not correctness — correlated errors win votes too (see Case 2).

Tree of Thoughts2023

Branch into multiple partial "thoughts," have the model rate its own thoughts, search over the best ones.

Shared: branching, scoring, pruning. Difference: in ToT the model grades its own homework; in ReasonTree an executed check outranks any model opinion.

Graph of Thoughts2023

Generalize the tree to a graph: branches can merge, loop, and refine each other.

Difference: richer topology, same self-evaluation. ReasonTree keeps the plain tree and spends the complexity budget on verification instead.

Monte Carlo Tree SearchAlphaGo era

The statistics-guided game search behind AlphaGo: simulate, score, expand the promising branches.

Shared: adversarial state-action search. Difference: our own experiments found visit-count MCTS cost 3–6× more with no quality gain at this scale — a small bounded search was enough.

Reflexion / Self-Refine2023

Let the model criticize its own answer and try again, possibly across attempts.

Shared: the skeptic pass of Case 4 is kin. Difference: where a real check exists, ReasonTree replaces self-critique with execution.

So what is actually different? One design rule, applied stubbornly: the model never gets the last word on anything a machine can check. There's a reason for that rule. A well-known study — Huang et al., "Large Language Models Cannot Self-Correct Reasoning Yet" (arXiv 2310.01798) — found that when models review their own reasoning without external feedback, they fix wrong answers about as often as they break right ones. Every method above that relies on the model evaluating its own thoughts inherits that ceiling. ReasonTree's bet is to route around it: executable states and verifiers wherever the domain allows (Cases 1–3), and where nothing can be executed (Case 4), honest labels instead of borrowed confidence — plus two habits that are rarer than they should be: a hard compute budget on every search, and the "underdetermined" output when facts genuinely don't pin down an answer.

We didn't just assert the difference — we ran a small version of the comparison. We built a one-level Tree-of-Thoughts-style harness (three independent proposals, then one evaluate-and-vote call; our own emulation, not the original authors' code) and pointed it at the same tasks, same model, no tools:

ApproachChess rescue puzzles (2)The two-alarms trapTypical cost/case
Raw Haiku — one stream0/2 — one illegal move, one wrongcommitted to "77%" after doubting it$0.01–0.07 · up to minutes
"Think in branches" prompt0/2 — both timed out at 90s
ToT-style, propose×3 + vote1/2 — voted for a refuted move on the othernamed the right conclusion, then answered "15.4%" anyway$0.2232 · 263s
ReasonTree — tree + verifier2/2 — in seconds, branches inspectableverified range 13.9–100% + the missing measurement~$0.014 · 5–21s
the ToT-style vote on the two-alarms question the branches knew — the vote caved
Proposal 2's insight is important—the true answer depends on unknown correlation—but that argues for a range or a recommendation to measure, not a specific guess. FINAL ANSWER: 15.4%

This is the most instructive failure on the page. Branching did surface the uncertainty — one proposal argued for a range. The vote even agreed with it in words. Then it picked a number anyway, because nothing structural stopped it. Branches without a verifier are opinions with better formatting.

Fairness requires the caveats: this is a tiny probe — two puzzles and one trap question, one model, our own ToT emulation rather than the official implementation, single runs. A proper head-to-head against the published Tree-of-Thoughts and Graph-of-Thoughts codebases, across many tasks and seeds, has not been done — by us or, to our knowledge, by anyone, for the verifier-gated setup. It's the obvious next experiment, and the repository is set up to run it. Until then, the claim we're comfortable making is narrow and matches everything above: structured branching helps a model surface doubts; only an executed check reliably converts doubts into a different answer.

Scoreboard

The numbers, side by side

chess: raw haiku
1/25
rated 1809-1819 · 30s cap
chess: reasontree
21/25
median 5.7s · same puzzles
chess 2200: raw sonnet 5
3/25
240s cap · median 57s
chess 2200: same adapter
18/25
median 3.0s · rescue 10/10
uncapped raw, 3 probes
1/3
one answer was an illegal move
alerts: raw / tot-style
\u201c77%\u201d / \u201c15.4%\u201d
two confident guesses at one unknowable number
alerts: reasontree
13.9\u2013100%
verified range · 14.8s
bug hunt: reasontree
$0.007
proven fix · 7.3s vs 19.6s raw
decision case
2 collisions
surfaced + assumptions labeled · $0.093
tot-style chess
1/2
~4 min and ~$0.20 per puzzle

Everything here is reproducible: the frozen puzzle set, the captured thought streams, the verifier code, the comparison harness, and the renderer that generated this very page are all in the open-source repository — github.com/uolkan/reason-tree.