Changelog
Kolofon's version history, release by release, straight from git — commit timestamps included. What went in, what broke, and what had to be fixed a quarter of an hour later.
Kolofon · 22 September 2026 · provisional

0.13.29 — stays with the entry
A fix to 0.13.28: a signed-in reader with a different language preference who opens an entry from an untranslated series stays with that entry instead of landing on the other version's home page. Version 0.13.28 takes a signed-in reader to the language version saved on their account, to the counterpart of the page they opened. A live test showed one case where this led to the wrong place: an entry from a series that has no translation. Such an entry gives the language switch no key, so its “counterpart” is the other version's home page. A reader who had been sent a link to such a text landed on the other home page instead of reading it. Since 0.13.29 a page without a key redirects only if it is itself the home page. An entry without a counterpart stays put — in the language it exists in.
Kolofon · 22 September 2026 · provisional

0.13.28 — language from the account
The account remembers the language version: the one it was created in, then whichever the reader deliberately switched to. A signed-in reader lands in their own version, on the counterpart of the page they opened. An account in a bilingual instance is one for both versions — the same database, the same login. Until now, however, it did not remember which language the reader reads in. Someone who created an account in English and then opened the site from a bookmark or a link landed in the Polish version and had to switch language every time. Since 0.13.28 the account gets the language of the version it was created in. After that, every deliberate switch — in the account menu or in the bar offering the other version — is saved as the new preference. A signed-in reader who enters a version other than the saved one lands on the counterpart of the same page in theirs: the same entry, the same series, the home page for the home page. Three safeguards. The redirect happens only if the counterpart exists — an entry from an untranslated series stays put instead of leading to a 404. At most one redirect every few seconds, so there is no way to loop. And saving the preference never holds up navigation for more than a fraction of a second. The browser language still decides nothing. The preference comes only from the reader's choice — the version they created the account in and their clicks on the switch — and a reader without an account sees what is at the address they opened.
Kolofon · 22 September 2026 · provisional

0.13.27 — an account under a prefix
In a language version living under a path prefix, account links and post-login redirects lost the prefix. Now the reader reaches their own version's account and, after signing in, returns exactly to the entry they were… A second language version can live under a path prefix, such as `/en`. The router knows routes without the prefix and adds it itself to every link it renders. The trouble is with addresses that bypass the router: plain links and redirect headers the browser reads directly. That was the case with accounts. The button in the wall inviting readers to create an account was a plain link and led to `/account` — an address of the default version, which has no such page, so the reader got a 404, and in the other language at that. The return address lost its prefix too. And after signing in with the email link, the server redirected to the bare account path or to `/`, again in the default version. Since 0.13.27 every engine address that bypasses the router gets the current version's prefix: the wall's link, the account page in post-login redirects — by email link and via external providers — and the home page. The return address is treated as a browser address, with the prefix, so after clicking the email the reader lands exactly on the entry they started from. A version at the root of the domain behaves as before — its prefix is empty.
Kolofon · 22 September 2026 · provisional

0.13.26 — no promises
After offline mode was withdrawn, the engine stopped promising it: the install prompt no longer mentions reading without a network, and the manifest route and offline page are gone along with the rest of the dead code. Version 0.13.25 withdrew offline mode, but the promise stayed in a few places. The install prompt told readers they would read “offline too”, feature descriptions announced a bundle of entries fetched in advance, and the code still held a manifest route and an offline page template that nothing called any more. Since 0.13.26 the install prompt says only what is true: an app straight from your home screen. The `/offline-manifest.json` route and the offline page template are gone, and the script that generates static files no longer creates the page. The engine documentation and the feature entry “07 · The app” describe the current state. Older essays in the Architecture series that described building offline mode stay — they got a note at the top saying the mechanism was withdrawn. They are a record of how the engine came about, not its manual.
Kolofon · 22 September 2026 · provisional

0.13.25 — only on request
Kolofon no longer has an offline mode. The service worker serves notifications only: it fetches nothing in advance, intercepts no requests and keeps no copies of pages. Version 0.13.24 tamed offline mode: instead of fetching every entry on the first visit, it fetched ten, with a delay and with pauses. The next step was simpler — offline mode is gone altogether. A page loads when the reader asks for it, and not a byte earlier. The service worker stays, but with a single job: push notifications. It fetches nothing in advance, has no `fetch` handler, so every request goes straight to the network as if there were no service worker, and it keeps no cache. On activation the new version deletes every cache left by previous ones. A reader who had week-old copies of pages stored on their phone will no longer see them instead of the current ones — on the next visit everything arrives fresh. The component that asked the service worker to fill the cache is gone from the engine. The service worker template shrank from over three hundred lines to eighty.
Kolofon · 22 September 2026 · provisional

0.13.24 — offline without a wave
Filling the offline cache no longer loads the server on a first visit. Instead of every entry at once: the ten newest, only after twenty seconds, with a pause between downloads, and never with data saving on. Instances can work offline: a service worker keeps entries in a cache so they can be read without a network. Filling that cache, however, was too eager. Right after installing, the service worker fetched every entry in the manifest, a few seconds later the page asked it for the same thing a second time, and switching language added a third set. In one of the instances that is more than a hundred entries per language. We measured it live, in the worker logs: one visit on a fresh phone plus a click on the language switch produced 267 requests in 75 seconds, 256 of them pages fetched in the background. Each needs server-side rendering, so on a plan with a CPU time limit some requests — including the ones the reader actually asked for — ended with error 1102. On top of that, several megabytes of mobile data nobody asked for. Since 0.13.24 the service worker stores only the page shell on install. Entries are requested only by the page, and carefully: twenty seconds after loading, at most the ten newest, once per session and language version. With data saving on or on a 2G connection — not at all. The service worker itself pauses a second and a half between downloads and does not accept a second queue while the first is running. Offline mode still works: the newest entries are at hand, and every visited page ends up in the cache through ordinary reading anyway. The engine's service w
Kolofon · 22 September 2026 · provisional

0.13.23 — vectors on demand
Search vectors can now load only on the first search. In the largest instance the main server bundle chunk went from 5 to 1.3 MB, and a cold worker start no longer processes the index for pages that do not use it. An instance hands semantic vectors to the engine as a glob of JSON modules. Until now it was an eager glob: all vectors went into the main server bundle chunk and were processed together with the rest of the code. In the largest instance that is 3.4 of the chunk's 5 MB — more than two thirds. The worker processes the main chunk on every cold start, that is, whenever a request lands in a fresh process. This happened for pages that do not use search at all. On a plan with a low CPU time limit, some of those requests ended with error 1102 — easiest to trigger by clicking quickly on a fresh phone, because several parallel requests then landed in new processes. Since 0.13.23 vector modules can be lazy: the instance passes a glob without `eager: true`, and the engine loads them only on the first search in a given process. The main bundle chunk in the largest instance went from 5 to 1.3 MB. The first search in a new process pays for loading the index, later ones run from memory; two simultaneous searches do not load it twice. An eager glob still works, so an instance that changes nothing behaves as before. Switching an instance over is one line in `instance.ts`.
Kolofon · 21 September 2026 · provisional

0.13.22 — results in the page's language
In a version without its own vectors, semantic search now shows the title, address and snippet from the entry in the page's language, not in the language the vectors were computed from. Semantic vectors can be shared by all language versions of an instance. That is a deliberate choice: the model is multilingual and the entry key is the identity of the material above language, so a question in English hits the same entry as a question in Polish. A separate index per language would be the same content computed twice — and it would weigh twice in the bundle. The catch is that a vector chunk carries the text it was computed from, and the result showed exactly that text. In a version without its own vectors, a reader asked in English and got a snippet in Polish. Since 0.13.22 the title, address and snippet always come from the entry in the page's language. The matched paragraph is carried over by position: the chunk is literally a paragraph of the source entry, and the translation keeps the paragraph layout, so it is enough to find its place and take the paragraph with the same number. When the layouts do not match, the entry's excerpt is shown instead of text in another language. An entry that does not exist in the given language does not make it into the results — the next one takes its place. The snippet trimming from 0.13.18 now works on text in the page's language, so the window lands on the sentence that shares a word stem with a question asked in the same language.
Kolofon · 21 September 2026 · provisional

0.13.21 — from home to home
On a home page that shows the stream, the language switch and the bar offering the other version now lead to the other version's home page rather than to its stream address. The language switch leads to the same material in the other version. It does so by a stable key: an entry, a series or a built-in page has a key shared by all languages, and the `/i/<key>` route turns it into an address in the given language. The stream has such a key too. The trouble is that the home page often shows the stream — with its own introduction above the grid, but the same view. The view passed the stream key, so the switch on the home page led to the stream address in the other version: from `/` to `/en/stream`, and from `/en` to `/strumien`. A reader who only wanted to change the language ended up on a different page from the one they came from. Since 0.13.21 the stream view recognises that it is on the home page and then passes no key. Without a key, the switch and the bar offering the other version lead to the home page: from `/` to `/en` and back. At its own address the stream behaves as before. The recognition goes by the address rather than by a new parameter. No instance has to add anything — the fix works wherever the home page shows the stream.
Kolofon · 21 September 2026 · provisional

0.13.20 — part number
An entry can carry a part number. Its tile in the series list and in the stream puts it before the title — “1. Title” — while the title itself on the entry page, in the feed and on the preview card stays unnumbered. Series read in order (`ordering: "sequence"`) list their entries from the first one. The order was right, but the tiles did not say which part was which. With a serialised series, a reader coming back a week later had to count tiles from the top to know where they stopped. Since 0.13.20 an entry can have a `part` field — the part number. The tile puts it before the title: “1. Title”, “2. Title”. This happens wherever there is a tile, which means the series list and the stream, where the number helps most, because entries from other series stand next to it. The number is given explicitly rather than derived from `order`. The reason is practical: a serialised series often opens with an introduction that comes first in the order but is not a part. Numbering derived from the order would shift everything by one. An entry without `part` looks exactly as before. The title itself stays unchanged. The entry page, the RSS feed and social preview cards carry the title without a number — the number tells you the place in the list; it is not part of the text's name.
Kolofon · 21 September 2026 · provisional

0.13.19 — as many columns as fit
A reader who has not yet chosen a column count gets as many as their screen fits: three on a desktop, two on a tablet, one on a phone. The switch highlights what is actually shown. Entry lists have a column switch: one, two or three — as many as the screen fits. The reader's choice is saved in the browser and, once signed in, on the account. The trouble was with readers who had not chosen anything yet, which means everyone on a first visit. A list series started with one column, a gallery with two, the stream with one. On a desktop that meant a narrow strip of text in the middle of an empty screen, while the switch next to it offered three. Since 0.13.19 no choice means “as many as fit”: three columns on a desktop, two on a tablet, one on a phone. This value is not saved. Only what the reader clicks is saved — so the same new reader gets three columns on a computer and one on a phone, rather than one everywhere because that is how the first visit happened. The series default does not disappear, but it now decides only the first render, before the browser measures the screen. The server HTML has to be the same for everyone, and starting with one column does not jump on phones, where most people read. Along the way the switch started highlighting what is shown. Choosing “three” on a screen that fits two displayed two columns but highlighted no button. Now it highlights the two — the button says the same as the screen.
Kolofon · 21 September 2026 · provisional

0.13.18 — a snippet to size
The snippet under a semantic search result is now at most 300 characters. It is cut at sentence boundaries, and the window starts at the sentence that shares a word stem with the query. From the start, semantic search has shown under each title the paragraph that decided the match — so the reader can see why they got this text. But the index computes vectors from whole paragraphs, and paragraphs vary a lot: from a single sentence to more than a dozen. The longest exceed a thousand characters. Three such results mean several phone screens before the reader sees the second title. Since 0.13.18 the snippet is at most 300 characters. The cut follows sentences, not characters: whole sentences go in up to the limit, because a sentence broken mid-word reads like a bug. Only a single sentence longer than the limit is cut at a word boundary. An ellipsis marks the side where something was left out. That leaves the question of which sentences to show. Search works on meaning and does not know which sentence of the paragraph tipped the balance. But when the query and the paragraph share a word stem — as in the Polish “masoneria” and “masońskim” — that sentence is the best evidence of the match, so the window starts there. The stem is the first five letters after stripping diacritics, computed only for words of four letters or more. Without a shared stem the window starts at the beginning of the paragraph. The index and the vectors do not change. Trimming happens at response time, so no rebuild is needed, and the limit is a single engine constant, `FRAGMENT_MAX`.
Kolofon · 16 September 2026 · provisional

0.13.17 — counters without zeros
Two counters on the entry page stop showing discouraging zeros. The view counter appears only from the tenth view; the comments section loses its count line — comments show only when there are any. Under a freshly published entry stood two numbers, both working against it. “1 view” in the byline and “0 comments” above the comments section. Each tells the reader the same thing: no one is here. That is exactly the signal a fresh text should not be sending. From 0.13.17 the view counter appears only from a threshold — ten views. Below it, it disappears entirely. We are not hiding the measurement, only the display: a view is still recorded exactly as before, we simply do not show the number until it grows large enough to give nothing away. The threshold lives in one engine constant, `MIN_VIEWS_SHOWN`. The comments section loses its count line. There is no more “0 comments” or “3 comments” — the number is not shown at all. Comments appear only when there are any, and below them, as before, stands the invitation to write one. Along the way the engine sheds the last string hardcoded into it: the fallback “Comments” shown while loading. The plural inflection of the word stopped being needed and goes too. Both changes have one justification. A counter is an ornament, not a function; when it reads a handful or zero, it stops being an ornament and becomes a record of emptiness. Better to show nothing than a number that puts people off. When there is something to count, the numbers come back on their own — from the threshold where they begin to mean something.
Kolofon · 14 September 2026 · provisional

0.13.16 — an account page without prices
Plan tiles with their prices opened the sign-in form. A price list in front of the address field asks the reader to settle the cost before they understand what the account is for. The account page used to open with plan tiles. Each carried a name, a price and a short note, and a price could have its previous one struck through beside it — all of it from the instance's strings. They were there for a sensible reason: so the reader would know the free account was not a trimmed-down version of something kept out of sight. The reason turned out to be weaker than the cost. A price list placed before the address field forces the question of money to be settled before the real question is even asked: what is this account for. A struck-through price adds a note of clearance sale, and a plan marked as not yet available promises something that could not be bought today even by someone willing. A page whose job is to take an address was opening with an advert. As of 0.13.16 the tiles are gone, and seven strings from the `plan*` family with them — the name, price, previous price and note of both plans — so instances no longer declare them in their `ui` block. This is not hiding by blanking the configuration: the markup is simply absent, and the string guard does not ask about keys the engine no longer knows. The wall for posts beyond the basic account is untouched. `wallPremiumBody` and `wallPremium` are a separate mechanism — they act on a post, not on the sign-in page, and never had anything to do with the plan tiles.
Kolofon · 13 September 2026 · provisional

0.13.15 — search results you can actually see
Results were appended below the field with no motion and no scroll. On a phone that looked like a broken button — the list sat below the fold and the page stayed put. The report came in the way the best reports do: I pressed search and never noticed anything appear. The results were on the page — all three, each with its paragraph. But they were appended below the field with no motion at all, and the page did not move, so on a phone, where the field sits halfway down the screen, the whole list landed below the fold. The button looked broken. Since 0.13.15 two things happen once the answer arrives. The page scrolls to the field, so the question and the first result stand together, with `scroll-mt-24` keeping clear of the header bar — without it the bar would cover the very field being scrolled to. The results then slide in one by one, seventy milliseconds apart, a short rise out of transparency. The motion lasts three tenths of a second, because its job is to say look here, not to entertain. The empty-result message arrives exactly the same way. No answer is also an answer, and it needs to be noticed too — otherwise silence after a button press means both nothing was found and nothing happened. When the system reports reduced motion, only the scroll remains, performed as a jump. An element that slides and fades is precisely what that setting exists to prevent — but hiding the result off-screen is not accessibility either, just a different failure.
Kolofon · 13 September 2026 · provisional

0.13.14 — the example list takes a frozen array
The string added in 0.13.13 was typed `string[]`, while instance config sits behind `as const`. The first instance that wanted to use the list failed the type check. The example list introduced in 0.13.13 was typed `string[]`. Instance config sits entirely behind `as const` — that is what keeps configuration values from being swapped at runtime — so the array arrives from there as `readonly`. The type check rejected every instance that wanted to use the new list, and the only way around it would have been dropping `as const` from the whole file. Since 0.13.14 `searchExamples` takes `readonly string[]`. The engine only ever reads that list, so nothing is lost. The fix surfaced at the first use, before 0.13.13 had gone up anywhere, and ships as its own number. A release that is already out describes what it did; fixes are not glued onto it.
Kolofon · 13 September 2026 · provisional

0.13.13 — the search hint types itself
Semantic search wants a sentence, and an empty field looks like every other search box on the internet — so it gets a word. Instead of asking for a sentence in words, the engine now shows one, typing itself. The semantic search added in 0.13.7 does not match words: the query goes to a model and is compared against the paragraphs of entries. It works best when a reader writes a full sentence about what brought them here. The problem is that an empty search field looks like every other search field on the internet, and those take a single keyword — precisely the input this search handles worst. The first instinct was an instruction in the hint: a full sentence, in your own words. True, and useless. It reads like a classroom exercise, and people look at the field rather than at the label above it. Since 0.13.13 the empty field suggests differently. An example query types itself in, character by character, holds for a moment, erases itself and gives way to the next one. Nothing is demanded; the shape of a good query is simply visible. The animation stops at the first touch — a click, a caret, any key — and never comes back, even if the reader leaves the field empty. A hint that resumes under someone's cursor is nagging. When the system reports reduced motion (`prefers-reduced-motion`), or the field already has content, there is no animation at all: the plain static hint stays, the same one that ships in the HTML and remains for anyone with JavaScript off. The sentences are interface strings, so they belong to the instance (`ui.searchExamples`). The engine knows none of them — the defau
Kolofon · 11 September 2026 · provisional

0.13.5 — a fourth skin: atelier
The brief fit in one sentence: clean white, elegant, with touches of brushed copper and bottle green. The engine got a fourth skin and not a single new component. A second professional business card went up on the engine, and the brief for its look fit in one sentence: the page should be clean, white and elegant, with touches of brushed copper and bottle green. None of the three existing skins could do that. “book” has warm paper, “dev” is dark, and “docs” is cool and navy. From 0.13.5 there is a fourth, `theme: "atelier"`. The background is true white. Green serves as ink, titles and the footer. Copper appears only in details: as the rule under the header bar and the drop cap in a post, because over a large area it stops looking precious. Headings are set in Bodoni Moda and text in Jost, since a serif with that much contrast tires the eye in a long paragraph at a small size. The instance loads the typefaces in `fontsHref`; without them the skin falls back to system fonts and still works. The brushed finish is two layers in one variable: a metal gradient and fine scratches on top. The first screenshot showed right away what not to do with it. In the `background` shorthand a given size applies only to the last layer, so the rule under the quote came out right, while the scratches spread across the whole paragraph as a grey box. Rules are now drawn with a pseudo-element. As with “dev” and “docs”, this is tokens and the cascade only. No component knows the skin exists, and the other three did not change by a single byte.
Kolofon · 11 September 2026 · provisional

0.13.4 — back to the default version
Switching to English worked. Switching back to Polish did not: the server read the language from the Referer header and sent the reader back to /en. The owner tried the switcher in production: Polish to English worked, English to Polish did not. The click seemed to lead to the Polish page and ended up on the English one again. Server functions go to a shared address with no prefix, so since 0.13.0 they got their language from a header, with the Referer header as a fallback. That fallback, though, applied to every request, not only to server functions. Clicking “Polski” on an English page sent a Referer of `…/en/…`, and the server treated the request for the Polish page as English. The tests did not see it because they used `curl` without a Referer. From 0.13.4 the header and the Referer count only under the server-function address, and a page gets its language from the path alone. Checked by clicking: four switches in a row, both ways.
Kolofon · 11 September 2026 · provisional

0.13.3 — R2 media under the prefix
A recording under /en/audio/… returned 404. The router strips the prefix from what it sees, but the media route read its key from the request itself. The second language merge covered a site that keeps its recordings and some photos in an R2 bucket rather than in the repository. A quarter of an hour after deployment a recording under `/en/audio/…` returned 404. Media routes take the object key from `request.url`, because params in server handlers are sometimes empty. The router's `rewrite` strips the `/en` prefix from what the router sees, but not from the request itself — the bucket was asked for `en/audio/…`, which is not there. The local test missed it for two reasons at once: repository files were already handled by another mechanism, and the local R2 is empty. From 0.13.3 `server.ts` strips the prefix from the address of every file request, and the language stays in the request context. Checked against an object put into the local R2.
Kolofon · 11 September 2026 · provisional

0.13.2 — no engine name in the browser
An instance can choose not to credit the engine. The footer credit went away, and since 0.9.0 so did the name in the bundle — but it stayed in class names, events and a header nobody read. Since 0.9.0 an instance with the credit switched off does not ship the engine name in its JavaScript bundle: the decision is made at build time and the dead branch disappears. That closed one place. Reviewing the 0.13.1 pull requests showed there were others. In the bundles of uncredited instances the engine name sat in the names of two animation classes and their keyframes, in four browser event names, and from 0.13.0 it was about to arrive in the HTTP language header. None of these places are visible on the page. All of them are visible to anyone who opens the file — which is exactly the person the credit is switched off for. There is a new guard, `check-engine-name.mjs`: after the build it goes through everything that is sent to the browser and stops if an uncredited instance carries the engine name. A credited instance passes straight away. An instance that used the old classes in its own content has to rename them — the only change required on its side.
Kolofon · 11 September 2026 · provisional

0.13.1 — the migration creates its own column
The 0.13.0 migration was meant to give pre-release events a language. In production it did not: the column is created by another module, and that one wakes up later. The first `status` after deploying 0.13.0 showed twelve old events with the page language “none”. Migration `0013` had recorded itself as done, moved the view counters correctly, and left the events alone. The cause is ordering. The `events.page_lang` column is created by the log module, but only on the first event write. The migration runs on the first view-counter read, which comes earlier. An `UPDATE` on a column that did not exist fell into a `catch` meant for a missing table, and nobody saw it. The dress rehearsal on a copy of production passed because it ran in a different order: the database merge script created the column before the first page view hit the copy. The test checked the correct scenario and said nothing about the one that actually happened. Filling in the events moved out of `0013` into a separate migration, `0013b`, which creates the column itself first. Databases where `0013` already ran get `0013b` on the next start. Both orders were checked for real this time: on a copy of current production and on a clean pre-0.13 database, with no script. The rule from here on: a migration creates every column it touches instead of relying on which module happens to wake up first in the isolate.
Kolofon · 11 September 2026 · provisional

0.13.0 — two languages, one deployment
Up to 0.12 a language version was a separate instance: its own subdomain, repository and database. From 0.13.0 one deployment serves several versions — the folder decides an entry's language, the path prefix decides the… For a month the English version of this site lived next to the Polish one like a neighbour through the wall: its own subdomain, its own repository, its own database, its own deployment. Every fix went out twice, and every new entry meant two pushes and two checks. 0.13.0 ends that arrangement. Both versions now run in one deployment, and the English one lives under `/en`. Two things, and neither is a new config field. **The folder decides an entry's language**: `src/content/posts` is the default version, `src/content/en/posts` is English. **The address decides a page's language**: a version registered with the URL `https://…/en` gets the `/en` prefix, because that is what its `url` says. Every Polish address stayed exactly where it was. The harder half was not routing. It was that `cfg()` is called in hundreds of places and until now always returned the same thing. Now it has to know which version the request is in. A global variable was out straight away: one Worker isolate handles requests concurrently, and two renders interleave at every `await`. On the server the language rides in AsyncLocalStorage, in the browser it is the prefix in the address bar. The test: eighty concurrent requests in Polish and English, not one string from the wrong version. The first idea for the prefix, the router's `basepath`, did not survive contact with TanStack Start: the server overwrites it on
Kolofon · 11 September 2026 · provisional

0.12.0 — the themes release
The number moves from 0.11 to 0.12 because the way the engine is used has changed, not merely how it behaves. An instance declares a theme and a few settings; the engine does the rest. The 0.11 line began with a site that looked the same everywhere and ended with something else: an instance declares what it wants to be, and the engine adjusts to that. This is a change in how the engine is used, not in what it does — which is precisely why the number moves up a level. Three themes: **book** — paper and old-style type, for a site built around reading prose. **dev** — dark and technical. **docs** — light, cool, documentation-like. They are not variants of one another; they are three different promises made to a reader in the first second. Alongside them, two prompts built from a single pattern — one for installing the app, one for enabling notifications — and propagation of releases to instances through pull requests, with guards deciding whether a pull request is ready or stays a draft. Bumping straight to 1.0 was tempting: themes sound like product maturity. But a 1.0 says “this is finished and stable”, and there are still parts of the engine I know will change. There is a stronger reason pointing the other way. **None of these fields is required.** An instance that declares nothing looks and behaves exactly as it did in 0.11.0 — verified after every one of the last ten releases, live, on every instance. A release that breaks nothing and demands nothing is not a major release. It is the next step. A number should describe reality, not ambition.
