Skip to content

Pages, variants and versions

You declare in code what can change on each page you route. This page explains how to shape that declaration, how everything in it is named, and what RoutingCat records as a version, so you can predict what a change in code will do. Build a page shows the code in full.

Choose a shape

A page is one page of your site, declared with its routes. A slot is a place on it that can change, and a variant is one alternative for a slot. Routing picks one variant per slot for each visit.

Give each idea the shape it needs:

Shape Use it for Example
One slot One thing to try Three headlines for home/hero
Several slots Things that can vary separately and still read well together A headline and a call to action
One slot whose variants each hold several pieces Pieces that must change together A headline and the line under it, written as pairs

Every combination must read well. Slots vary independently, so a visitor can get any headline with any line under it: 3 headlines and 2 lines make 6 combinations, and each must read well. Routing also judges each slot’s variants by their own effect: it doesn’t learn that a headline works only beside a particular line. So when pieces must match, put them in one slot, as parts of the same variant.

Combinations have no limit of their own, since no page is built once per combination: a page that carries every variant holds them all in one HTML, the same for every visitor, and each hidden variant adds to its weight. Limits and defaults gives the limits on slots and variants.

Defaults, keys and addresses

Every slot has a default: the variant your site shows today. The control always sees it, and the page shows it whenever RoutingCat doesn’t pick, as in development. A default can’t be paused or retired; promote another variant first.

Keys name pages, slots and variants: lowercase letters, digits, - and _, at most 40 characters. A variant’s history, scorecards and evidence belong to its key, not to its content. A retired key stays reserved: declaring it again brings back the retired variant, history included. So a new idea always gets a new key.

Addresses join the keys, and the commands take them:

Address Names
home A page
home/hero A slot
home/hero:oneclick A variant, at its current version
home/hero:oneclick@v2 One version of that variant

A version can also be named by the start of its content hash, as home/hero:oneclick@7f3a1c; show prints the hash beside the version.

What makes a version

A version is one state of a variant’s content. The build registers a new one when a deploy carries content that differs from the variant’s current version. Versions are numbered @v1, @v2 and so on, and every version is kept.

What counts as content is a variant’s markup, as your template writes it. Reformatting it makes no version: its line breaks and indentation, the quotes around its attributes’ values and their order, where template syntax doesn’t write them, and whitespace the page doesn’t show, inside its tags, around and inside block elements such as div, p, li and section, and around a br. Whitespace that shows is content: removing the space between two words, or between two inline elements as in <b>Fast</b> <i>private</i>, makes a version. So:

  • data a template renders inside a variant, such as a product’s title, makes no version: the variant is one version on every page it renders;
  • an include inside a variant, such as Blade’s @include, counts as the call, so editing the included file makes no version;
  • an image is identified by its URL, so new bytes at the same URL make no version;
  • what marks the variant that shows, hidden, data-nosnippet and the default’s style="display:contents", is no part of it, nor is the stamp push writes, so moving the default to another variant, as after a promote, makes no version.

An upgrade of routingcat that changes how a version is identified keeps your versions: the first deploy after it finds each variant’s version under its new identity, and makes none.

Its first push stamps each variant’s hash under the new identity, where it differs: commit what it changed, since push --check fails until you do.

Same key or new key

The key decides what a change is compared with in its scorecard:

Change Key Result Its scorecard compares
A fix or a refinement The same key A new version of the variant The new version with the one it replaced, over their own periods
A new idea A new key A new variant The variant with the slot’s default, at the same time

A comparison at the same time is the fair one: both sides meet the same visitors, days and campaigns. A before-and-after comparison can’t separate the edit from whatever else changed meanwhile. So edit under the same key to fix or polish an idea, and put a different idea under a new key. Routing treats them differently too: an edit builds on what the variant showed, while a new variant starts cautiously.

Deleting a variant from your code retires it at the next production deploy, keeping its history.

Parents

A new variant can declare where it came from, with parent and relation: fix, refine or fork for one parent, recombine for several. A parent is a variant of the same slot, by key or at a version, as current@v2.

Both go in routingcat.config.json, under variants, by the variant’s address, beside its name, description and tags.

The relation is recorded in the variant’s history, and show lists each version’s parents. One parent declared as a fix, a refinement or a fork also gives the new variant a head start: it begins from part of what its parent showed, never all of it, and show says its signal “borrows from” that parent. A recombination starts fresh. An edit under the same key always builds on the version before it, declared or not.

What isn’t captured

A version records only what you declare, and show lists, for each version, what it doesn’t capture: shared styles, behavior, data that depends on the request, third-party embeds, state that exists only in the browser, and content fetched at run time.

A variant written in markup is declared as your template writes it, not as it renders, so the data a template fills in, such as each product’s title, and the files it includes aren’t captured either.

So a change to a shared stylesheet, or to a price fetched when the page renders, makes no version and opens no scorecard. Each deploy’s commit still records it.

Next