Lightning Jar - Web Studio Lightning Jar Wordmark

barkup-bench

barkup-bench is our open research project measuring how large language models read and edit structured document trees. Every study is pre-registered: the hypotheses, task corpora, prompts, and analysis plan are committed to a public repository before a single model is called, and the results are published as found, corrections included.

The series so far: nineteen studies, more than 13,000 scored model runs, four models, trees from 5 to 1,000 nodes, and editing sessions up to 36 edits long. The findings compress to one sentence: give every node a stable id, and never make the model reproduce anything it is not changing. Everything the benchmark validated ships in the open-source barkup library, linked below with the full article series.

barkup-bench · pre-registered · corrected 2026-07-06 · studies F–S

Every id-stable interface works — until trees get big or sessions get long. Then only anchored patches do, and they barely need to see the tree. Finding where to look costs one search call, and remembering the session costs two worked examples — even 36 edits in.

Main study: 200 seeded tasks × 6 conditions × 4 models × 2 regimes, temperature 0 (July 2026), plus follow-up studies G (tool-history footgun), H (300–1000-node size extension), I/J (focused views: partial-context patches, JSON and HTML renderings), K (12-edit sessions under four serialization policies), L/N (grounding without ids, then the retrieval ladder), M/O/P (session memory, positional views, synthetic history), Q/R (fan-out edits and their fixes), and S (36-edit long sessions). All numbers below are protocol-v2 corrected — the original interface-reliability gaps were an artifact of conversation histories that hid the model's own tool calls (vercel/ai#16840). Charts show parity prompts, models pooled unless noted; Wilson 95% intervals. Conditions: A HTML + whole-tree rewrite, B JSON + rewrite, C JSON + mutation tools, D HTML + tools, E JSON Patch, F id-anchored patch (pre-registered addendum, BRIEF-F.md).

−2.0pp
corrected A vs C overall: 91.9% vs 93.9% — tools at slight-edge parity, not −5.3pp behind
3.8→71%
gemini-flash multi-turn tools success when its own tool calls become visible in history (the footgun)
≥99.3%
first-pass validity in every arm — HTML and JSON fluency tied
87–100%
anchored patches (F) at 300–1000 nodes, both model tiers — where rewrite falls to 0–80%
4s vs 10min
solved 1000-node edit: F $0.26 + 4s vs rewrite $0.88 + 597s (sonnet)
−98%
input tokens with a minimal focused view at ~1000 nodes (85.6k → 1.5k) — accuracy statistically unchanged (Studies I/J)
13–0
late-session paired wins, per-turn views vs serialize-once (sonnet, Study K) — and views cost 4× less
7–9pp
the price of grounding a human-style description with the whole tree in context (Study L) — before the search tool
1 call
median find_nodes searches to ground an id-free edit — 43/45 sonnet (= its oracle bound), 39/45 gemini, at ~10% of full-tree input (Study N)
15/20
stateless sessions ending byte-perfect even with exact positions printed on every node (history: 19/20) — memory isn't doing arithmetic (Study O)
2 examples
replace a session's entire history: ~900 canned tokens in the system prompt restore stateless sessions to full-history accuracy, at half the cost (Study P)
~½ of N
targets actually edited when one prompt asks for N edits — fan-out degrades every strategy, even oracle retrieval (Study Q)
90/90
fan-out tasks solved by app-side decomposition — 674/674 single-target subtasks, both models, at ⅓ the cost of a whole-tree prompt (Study R)
5.6×
what keeping history costs vs two worked examples across a 36-edit session (449k vs 81k input tokens) — accuracy at parity, no late-session decay (Study S)

H2 · task success by tree size

At benchmark sizes (5–150 nodes), no interface dominates

Whole-tree rewrite (A, B) leads granular tools (C, D) at every size tested. The gap peaks on small/medium trees and narrows — but never reverses — at ~150 nodes. JSON Patch (E) collapses to 69.6% on large trees — and the pre-registered addendum condition F (id-anchored patches) recovers it exactly to rewrite level at the lowest token cost.

Data table — success by condition × size (parity, pooled)

H4 · multi-turn reference tasks, by model

Corrected: multi-turn reference edits are near-parity

Success on “insert a node, then edit it by the id from your own output” — protocol v2. With the model's own tool history visible, every interface is near-parity (A 88.1% vs C 91.3%, n.s.); gemini's residual tools deficit is phase-1 editing accuracy, not follow-up dropout. Zero id-reference failures in any arm, ever. The dramatic v1 gaps live in the footgun chart below.

Data table — reference-family success by model × condition (parity)

H3 · mean tokens per solved task

Rewrite is cheap where trees are small; HTML is the terser artifact where they're large

Tools arms (C, D) resend a growing conversation every call, so they burn 4–5× more tokens on small/medium trees. At ~150 nodes the whole-artifact arms grow too — and the HTML dialect (A, 15.6k) undercuts JSON rewrite (B, 23.0k) by ~30%: the one place the format measurably matters.

Data table — mean total tokens per solved task (parity, pooled)

Overall · success per model × condition (parity, 200 tasks each)

Frontier models don't care; smaller models do

Per-cell task success. Down the sonnet-4.5 and gpt-5.4 rows the interface barely matters; down the haiku-4.5 and gemini-3.5-flash rows the tools arms give up 10–17 points against rewrite.

Study G · the tool-history footgun

One hidden SDK default, two very different benchmarks

The original +33pp multi-turn gap was manufactured by conversation histories that omitted the model's own tool calls (the AI SDK v5→v7 response.messages trap). Same tasks, same prompts — only history construction differs. Under corrected history, all 2,160 Study G cells pass.

Data table — reference-family tools success, v1 vs v2

Study H · 300–1000 nodes

The crossover, found: above ~300 nodes, only anchored patches hold

Whole-tree rewrite becomes frontier-only at scale (gemini-flash: 0/15 at ~1000 nodes; sonnet needs a streaming transport and ten minutes per rewrite). Anchored patches hold 87–100% for both tiers at every size — $0.26 and 4 seconds per solved 1000-node edit. Positional patches decay to ~10%. Solid lines: sonnet-4.5; dashed: gemini-3.5-flash.

Data table — success by model × condition × size (n = 15 per cell)

Studies I & J · focused views

The model doesn't need to see the tree: a ~1.5k-token view matches the full 85k-token input

Show only the path to the referenced nodes plus their child lists (everything else collapsed or omitted with a count), and anchored-patch accuracy is statistically unchanged for both models at every size — sonnet on the minimal view went 45/45 — while the view's size grows with tree depth, not node count. Rendering the view in barkup's HTML dialect instead of JSON changes nothing on accuracy (p = 1.0 in all four paired comparisons) and is 9–24% terser; it shipped as barkup/view in 0.3. Caveat: this is the oracle bound — instructions name their target ids. Solid: sonnet-4.5; dashed: gemini-3.5-flash.

Data table — median input tokens and success by model × input × size (n = 15 per cell)

Study K · 12-edit sessions

Sessions drift unless you re-show the tree — and showing a fresh view every turn is also the cheapest policy

Twelve sequential patches against one evolving tree. Shown the tree once, sonnet decays to 83.8% by the last third (stale ordinal placements); with a fresh ~1.5k-token minimal view every turn it stays at 100% (239/240 steps) for a quarter of the tokens — the once-shown tree rides along in history every turn anyway. Whole-tree rewrite as a session protocol fails structurally: gemini silently corrupts state (all 44 failures valid-but-wrong; 2/10 sessions end intact) and one sonnet session deterministically exhausted the 200k context window at step 11. Solid: sonnet-4.5; dashed: gemini-3.5-flash.

Data table — per-step success by session third, end-state, and mean tokens per session

Study L · grounding without ids

Finding the node is the expensive part: grounding costs 7–9 points, and navigation is a frontier-only trap

Same edits, instructions rewritten without ids ("the image-atom named 'maple-ember'"), every description verified to match exactly one node. With the full tree in context, models ground at 84–87% (vs 91–96% with ids). Letting the model navigate a skeleton with an expand tool matches the oracle on sonnet — at a median of 54 expansions, costing MORE than showing everything — and collapses on gemini, mostly by exhausting its budget without an answer. Naive lexical retrieval is the floor it was designed to be. The pre-registered gate failed: no partial-context mechanism was both accurate and cheaper — until Study N (next chart) swapped the expand tool for content search.

Data table — success, input tokens, and failure anatomy by condition (45 tasks per cell)

Study N · the retrieval ladder

Stop walking, start searching: one find_nodes call grounds the edit on both model tiers

Same id-free tasks as Study L; the expand tool replaced by a single content-search tool (a few words in, the 5 best keyword matches out, shown in place). The frontier model matches its id-oracle bound exactly — same 43/45, same two failed tasks — at a median of one search call and ~90% less input; gemini jumps from 23/45 (navigating) to 39/45 (16–0 paired, p < 0.001), its full-tree score at 3% of the cost. Two more rungs: swapping the keyword matcher for text-embedding-3-small changed nothing (target coverage 23/45 vs 24/45 — embeddings can't resolve "the 3rd block inside atlas"), and two-stage grounding (gemini reads the tree, names the ids, sonnet patches a focused view) holds 41/45 with the frontier model's median input at 1,484 tokens (−97.4%). The Study L gate, re-tested, passes twice.

Data table — success, input, and mechanism by condition (45 tasks per cell)

Study M · stateless sessions

The view carries the state, but history still earns its keep

If a fresh view arrives every turn, does the model need conversation history at all? No — statelessness confirmed the constant-cost economics (~1.3k input tokens at step 1 and step 12 alike) but failed the accuracy gate: sonnet lost 7 steps to 0 against full history (p = 0.016) and end-state integrity dropped from 19/20 sessions to 13–14/20, with failures concentrated in late-session placement edits. A 2-exchange window sits in between, leaning inadequate. Guidance at the time: keep the history AND the per-turn view. (Study P, two charts down, found what history was actually providing — and how to replace it.) Solid: sonnet-4.5; dashed: gemini-3.5-flash.

Data table — per-step success by session third, end-state, and cost shape

Study O · positional views

Printing the position on every node does not rescue stateless sessions

Study M's stateless failures were all placement edits, so Study O annotated every view child with its true 1-based position (plus a prompt line mapping ordinals to anchors) and re-ran the 2×2 of history × positions. The rescue failed: stateless accuracy moved 3–1 / 1–0 vs plain stateless (n.s.), and sessions ending byte-perfect stayed at 15/20 vs full history's 19/20 — models misplaced nodes that had the correct position printed on them. Whatever history contributes to placement, it is not arithmetic. Positions with history were descriptively the best cells in the whole series (gemini: 20/20 end-states, 60/60 late placements) but not significantly better than history alone: harmless, possibly mildly helpful, not a substitute for memory. (Study P, next chart, found the actual substitute.)

Data table — late-session success, placement class, end-state, and cost by policy

Study P · synthetic history

History was a teacher all along: two canned examples replace the whole conversation

If history isn't state (the view carries that) and isn't positional help (Study O), maybe it's worked precedent — and precedent can be faked. Two unit-tested examples (an ordinal insert and a move, on a tree the model never edits, ~900 tokens) restore stateless sessions to full-history accuracy on both models: worst paired difference vs K-view anywhere is 2–0 (n.s.), end-states back to 18–20/20, and gemini's examples arm goes 60/60 on the late placements that defined the M failure class — with 20/20 byte-perfect endings. The system-prompt framing ties the fake-turns framing, so the value is content, not conversation. Flat ~2.1k input/step forever, half of keep-history's cost at 12 edits, no context ceiling. The session guidance is revised: fresh view per turn + two worked examples in the system prompt.

Data table — late-session success, placements, end-state, and cost by policy

Study Q · fan-out edits

"Change every X inside Y" breaks everything — including the oracle

One instruction, 2–32 targets, on the same large trees. Even with retrieval solved (every target visible in the view), models finish only part of the set: 62–69% overall, ~45% at 7+ targets, failures 100% partial coverage. The 0.4 search recipe fails its gate (median 6 calls instead of 1; a third of runs over 100k input tokens; −24 pp vs full tree on gemini). And the series' first model inversion: sonnet is significantly better with a view (p = 0.022), gemini significantly better with the whole tree (p = 0.008) — no context strategy is model-independent here. Study R then tested the fixes: prompt-side interventions (a worked fan-out example, a coverage checklist) do NOT rescue it — but decomposition, measured directly, is perfect: the app enumerates targets and issues one single-target edit per node, 90/90 tasks on both models (674/674 subtasks, zero failures) at ~⅓ the input cost of a whole-tree prompt. The flat line at the top is the recipe. Solid: sonnet-4.5; dashed: gemini-3.5-flash.

Data table — success by condition × target count, failure anatomy, and tokens

Study S · long sessions

36 edits later, nothing broke — except the cost curve

Every prior session study ran 12 edits. Study S ran the two surviving recipes through 36 (10 new sessions, seed committed) and both held: full-history S-view went 719/720 steps across both models, stateless-plus-worked-examples S-system went 713/720 with no late-third decay (98–99% at steps 25–36 — step 36 is taught as well as step 1), McNemar parity everywhere, zero context ceilings, zero blocked steps. What diverges is cost: keep-history's median per-step input grows linearly to ~24k tokens by step 36 while the stateless recipe stays flat at ~2.1k, which compounds to 449k vs 81k input per session — 5.4–5.6×, against a pre-registered prediction of ≥3×. The gate passed on both models; the worked-examples recipe is the measured default for long sessions. All seven S-system step failures were placement-class (insert/move), the class Studies M/O/P mapped. Solid: sonnet-4.5; dashed: gemini-3.5-flash.

Data table — per-third success, end-state, and tokens per session by recipe
Pre-registered design, corpora, prompts, corrections, and all analyses live in the barkup-bench repository (REPORT.md, including the protocol-v2 correction and the Study G–S addenda). Upstream bug report: vercel/ai#16840. Reading accuracy (H5) tied across formats and is omitted from the charts.

The Packages

Open-source software generated in response to the research, all MIT licensed.

@kevinpeckham/barkup

The library the benchmark shaped. A grammar codec for authoring typed trees as HTML, plus everything the studies validated: id-anchored patches, focused views, content search, and deterministic selection. Every feature was gated on a pre-registered study before it shipped.

barkup-bench

The harness itself. Pre-registered briefs, task corpora, committed seeds, the full REPORT.md, and every correction, published as found.

@kevinpeckham/barkdown

The sibling package. A Markdown round-trip codec born from the same discipline of testable guarantees: one round trip canonicalizes any document, a second is byte-identical.

The Full Series

Every post in the barkup-bench series, in order. Start at the top for the whole story, or jump to the capstone, Stable IDs Are All You Need.

  1. HTML as a Native Data Format for LLMs: Why We Encode Our Data in Markup Instead of JSON Jul 4, 2026
  2. We Benchmarked It: What Held Up in 'HTML as a Native Data Format for LLMs', and What Didn't Jul 6, 2026
  3. barkup 0.2: We Shipped What the Benchmark Told Us Jul 6, 2026
  4. A Deprecated Accessor That Still Typechecks Broke My Benchmark (and Maybe Your Agent) Jul 6, 2026
  5. We Found the Crossover (It Wasn't Where Anyone Looked) Jul 7, 2026
  6. The Model Doesn't Need to See Your Tree Jul 7, 2026
  7. Your Agent's Session Is Drifting (and the Fix Is Cheaper Than the Bug) Jul 7, 2026
  8. barkup 0.3: Focused Views, or Why the Model Doesn't Need to See Your Tree Jul 8, 2026
  9. Stable IDs Are All You Need: Seven Studies on Letting LLMs Edit Trees Jul 8, 2026
  10. We Tried to Delete the Hard Parts. The Benchmark Said No. Jul 8, 2026
  11. Then We Found the Cheap Part: One Search Call Grounds LLM Tree Edits Jul 9, 2026
  12. barkup 0.4: The Model Finds the Node Now Jul 9, 2026
  13. Your Agent Doesn't Need a Memory: Two Worked Examples Replace Session History Jul 10, 2026
  14. barkup 0.5: Your Code Finds the Targets Now Jul 10, 2026
  15. The Thirty-Sixth Edit: Long LLM Sessions Don't Need Memory Either Jul 10, 2026