The model picker brought more than models

A model picker needs a model list. In Kumyu Model Council, refreshing that list used the workspace snapshot operation: an operation built to gather more of the application's state. The screen requested a convenient existing response and used only part of it.

Nothing was visibly broken. That was what made this worth finding. The extra work had a legitimate implementation, a successful response, and a caller that could render the result.

We inspected all eight applications in the Kumyu monorepo and changed four concrete mechanisms. The common thread was the amount of work attached to an otherwise ordinary action: choosing models, opening an article, filtering a collection, or revisiting a page.

The measurements below come from local builds and fixed-input tests. Deployment-source verification and production browser measurements remain unfinished; no new production LCP or INP improvement is claimed.

The size, operation-count, build, and test results below use source baseline 641e4afb with the same inputs before and after the patches: Node 26.7.0, zlib 1.2.12, esbuild 0.28.2, and TanStack React Router 1.170.41. Subsequent dependency integration on main, including Router 1.170.44, is outside that comparison. Regression checks against the final integrated dependencies remain unverified.

Shrink the question before optimizing the answer

For the model picker, we changed the caller to the existing list_models operation. It already answered the actual question, so no additional endpoint or caching layer was necessary.

The local comparison used the same model catalog and default model choices, with no discussions and no configured provider keys. We measured the UTF-8 size of uncompressed serialized JSON; these are response-body bytes, not compressed network transfer sizes.

Model-list fixture Before, snapshot JSON After, model-list JSON Reduction
English 4,747 B 591 B 87.6%
Japanese 5,312 B 591 B 88.9%

The fixture also reduced the database work for this read from two SQL queries to one. Catalog entries and default model choices remained equal. That last check matters: returning fewer bytes is easy if useful choices disappear.

This does not mean Model Council became 88.9% faster. The table excludes network latency, authentication, browser rendering, model-provider time, and production data volumes. It establishes something narrower and reproducible: the model-list refresh asks for less information and performs less database work.

The practical question is useful beyond this application: what is the smallest existing operation that answers this screen's question? A convenient whole-application snapshot can become an accidental dependency of every small control.

Static HTML can still trigger a second data load

Kumyu Learn already renders article bodies into static HTML. Reading does not depend on a server LLM, an external font, or JavaScript successfully assembling the article. The application also keeps route data separate from the entire article corpus.

Those are good starting conditions. They do not automatically settle what happens when React hydrates the page and the router resumes its loaders.

The article and archived-revision routes had not declared their own freshness policy. TanStack Router's documented default staleTime is zero; reusable successful loader data is immediately stale, and an explicit router.load() can revalidate it.

We reproduced the problem with Learn's actual makeRouter, using the deterministic prerender clock and then switching to client mode, as hydration does. The subsequent history load executed the article loader a second time before the change. After the change, it reused the accepted result: two loads became one. Distinct article slugs, revision numbers, and locales still fetched their own data in the regression test.

The source change makes the static article and archived-revision routes explicit:

staleTime: Infinity

Here, Infinity governs the router's freshness decision for a reusable loader result. HTTP-cache retention and garbage collection remain separate. An already open page will not automatically receive every future article revision; a document reload or explicit invalidation has its own behavior.

This is a targeted policy for build-produced reading data. Applying it to live balances, editable settings, or a changing conversation would require a different freshness decision.

Source: TanStack Router's data-loading guide, sections on defaults and disabling automatic stale reloads. The load counts above are local regression-test results.

Search was asking the DOM the same questions again

Kumyu Catalog's collection is already present in the initial HTML. JavaScript adds filtering, saved items, comparison selection, and sorting. We kept that arrangement.

The filtering path repeatedly constructed normalized search text and looked up the corresponding card element. It also appended cards even when the requested sort order had not changed. A search input could therefore ask the browser to repeat work unrelated to the changed query.

The revised path prepares normalized metadata and card references once, then reuses them. It changes DOM order when the sort mode changes and leaves that order alone when only visibility changes. Search still has access to the same metadata; this is not a reduction of the searchable collection.

We ran the real Catalog script in a local VM harness against all 64 entries in each locale and 20 queries. The harness counts operations; it does not simulate layout, painting, or input latency.

Counted operation Before After
Search-string normalizations, per locale 1,300 84
Card moves during initialization, per locale 64 0
Card moves for the 20 English queries 270 0
Card moves for the 20 Japanese queries 251 0

Zero query-driven moves does not mean sorting stopped working. A new sort mode still changes order; a query-only change no longer moves cards unnecessarily.

A second change limits a motion-demo stylesheet to pages that use it. Across 171 generated routes without those demos, HTML no longer references that file: 11,682 B raw, or 3,031 B gzip. The search implementation grew by 246 B gzip. That is the tradeoff: slightly more reusable preparation code, fewer repeated operations, and fewer irrelevant stylesheet references. Browser caching and compression still determine actual transfer savings.

Existing Catalog checks passed for 204 HTML files and 6,301 links, along with 16 existing tests. Those checks support output and contract consistency. They do not measure input latency or establish an INP improvement.

The right next measurement is an actual input-and-sort trace on a fixed browser and collection. Counting eliminated calculations and DOM operations tells us why a change is plausible; it does not tell us how many milliseconds a reader notices.

The cache policy existed; two scripts needed to join it

Home already had a content-hashed asset pipeline and long-lived immutable caching for the assets it processed. The theme script and character-motion script still used stable names outside that pass.

We added those scripts to the existing minification and content-hash process. When script contents change, their generated URLs change too. HTML points to the generated names; the same immutable-asset policy can cover them.

The deterministic build comparison also showed a smaller output:

Shared script Raw before Raw after Gzip before Gzip after
Theme 1,898 B 1,049 B 752 B 496 B
Character motion 10,506 B 7,699 B 3,781 B 3,110 B
Sum of the two files 12,404 B 8,748 B 4,533 B 3,606 B

The sum of their gzip sizes fell by 20.4%. Those are locally compressed build artifacts, not measured production transfers. The Home build and 191 tests passed. Minification and hashing use the existing delivery path, with no second cache-version mechanism.

The distinction between an asset URL and the HTML that references it is the useful part. An immutable asset can be reused while fresh because that URL's contents stay fixed. HTML needs its own publication and revalidation policy so it can point to new asset URLs. Personalized responses need a separate privacy decision.

Source: MDN's Cache-Control reference, sections on immutable and hashed static assets.

Eight applications do not share one bottleneck

Reviewing the whole monorepo does not justify rewriting every application. We separated changes with concrete evidence from paths that need a different measurement environment.

Application Scope of this investigation Change or remaining limit
Home Static page delivery and shared scripts Joined two scripts to the existing hashed-asset pipeline
Learn Static article routes and router freshness Declared freshness for article and archived-revision loaders
Catalog Search metadata, card operations, page styles Reused search preparation and card references; limited motion CSS
Model Council Model-list refresh and response contents Used the existing model-list operation instead of the workspace snapshot
Channel Source-level review No production performance conclusion from this review
Matching Source-level review Authenticated interactions were not benchmarked
Computer Use Stored snapshot and listing boundaries Full snapshots already live in R2, with summaries in D1; listing growth remains unmeasured
Agent Lab Source-level review No production performance conclusion from this review

Computer Use's large snapshots were already separated from its database summaries. We kept that boundary. Whether its cursor-based listing grows too expensive needs its own workload and measurement.

Authentication, ownership checks, and durable writes also stay in place. A query that enforces a permission is not redundant merely because it takes time.

A smaller response is evidence; a faster website needs another measurement

The most tempting sentence in a performance article is a percentage followed by “faster.” This investigation does not support that sentence.

A raw JSON size, a loader invocation count, a removed stylesheet, and an input trace answer different questions. web.dev's LCP guide separates response time, resource discovery, transfer, and rendering. Its distinction between laboratory and field data is why we do not turn these local results into a real-user percentile.

Local output and regression checks support the changes, including Learn's frontend build, prerendering, selected tests, and generated-output verification. The dependency audit could not reach the registry, CI execution was blocked before application steps, and Cloudflare's active source could not be read in this session. Those checks remain unverified.

Once those checks are available, the comparison needs fixed before-and-after builds, alternating runs, the same viewport and network conditions, and verification that the active deployed source did not change during the sample. The changed interactions matter too: model-list refresh, article reload and navigation, search, sort, and revisits.

Try the investigation on one ordinary action

Choose a small action that already works. Write down exactly what it needs, then compare that list with the actual response fields, database reads, loaded files, and DOM changes.

Keep one invariant beside each candidate removal: model choices stay equal; article text stays readable without JavaScript; search finds the same items; sorting preserves its requested order; a new asset version receives a new URL. Remove one unnecessary unit of work, then check both the invariant and the affected metric.

AI agents can assemble a working route quickly. A whole-state response, an unspecified cache default, or a repeated DOM operation can survive because the happy path looks correct. The useful review is concrete: which request, query, byte, or operation can disappear while the reader still gets the same result?

That question produced the changes in this audit. Measuring the reader's experience after deployment is the next piece of evidence.

MENTAL MODEL / REASONING ORDER

From an announcement to your own decision.

Primary sources

Compare the announcement with the conditions in the paper and official documentation.

Sources

Publication dates belong to the source; access dates record when it was checked. Community observations are separate from official statements.

01
Official documentationweb.dev: Optimize Largest Contentful Paint ↗web.devPublished: 2020-04-30 · Accessed: 2026-10-23
02
Official documentationMDN: Cache-Control header ↗developer.mozilla.orgPublished: Unknown · Accessed: 2026-10-23
03
Official documentationTanStack Router: Data Loading ↗tanstack.comPublished: Unknown · Accessed: 2026-10-23
Saved in this browser only.