Breeding
Construction of one new organism from living parents by one of six operators, three of them pure code and three of them a call to a model.
Breeding is the construction of one new organism in the Rorschach Lab: a single operator is chosen, applied to zero, one or two living parents, and the resulting genome is either stored or thrown away. Six operators are in rotation, three of them pure code that returns in milliseconds and three of them a call to a model. One birth is attempted per track per pass of the loop, and a birth that is rejected leaves nothing behind.
Parent selection
The breeding pool for a track is every living organism whose code has rendered at least once. If no living organism in the track has rendered, the pool falls back to the whole living set.
With fewer than two organisms in the pool, the operator is always fresh and no parent is picked at
all. Otherwise the first parent comes from one of two tournaments, both of which sample three
organisms at random from the pool:
- The rating tournament keeps the sampled organism with the highest fitness. This is the default path.
- The novelty tournament keeps the sampled organism whose nearest neighbour in the pool is
farthest away, which is the outlier rather than the champion. It fires on a probability held in
lab.config.json, and only once the pool holds at least four organisms.
A two-parent operator picks a partner from the rest of the pool. Phylum fidelity applies first: on a configured probability the candidate list is narrowed to organisms sharing the first parent’s phylum, and the narrowing is skipped when that phylum has no other members. That probability drops to a second, much lower configured value while the track is in a diversity crisis, so an inbred pool is pushed to outcross. The remaining candidates are ranked by token distance from the first parent, farthest first, and one of the top four is taken at random. A one-parent child inherits its first parent’s phylum, so a two-parent birth that crosses phyla is the only event that mixes lineages.
The operator set
The weights below are the lab’s current configuration in lab.config.json and are drawn as a
cumulative roulette; a roll past the last weight yields mutate. In a diversity crisis a share of
passes bypasses the roulette entirely and takes fresh, which is the only operator that can add a
lineage rather than enlarge one.
| Operator | Weight | Model call | Effect on the genome |
|---|---|---|---|
jitter | 0.12 | No | Rewrites a random subset of the numeric alleles in one parent’s code. |
splice | 0.16 | No | Substitutes matched loci from the second parent into the first, at a per-locus rate drawn between 0.3 and 0.7. |
graft | 0.07 | No | Copies a locus the second parent has and the first does not into the first parent’s code. |
mutate | 0.27 | Yes | Asks for a changed version of one parent that keeps its identity but moves decisively along two named aesthetic axes. |
crossover | 0.13 | Yes | Asks for one hybrid of two parents that resolves their conflict on one named axis instead of averaging them. |
fresh | 0.25 | Yes | Asks for an organism written from scratch against the directive, with no parent. |
A free operator is jitter, splice or graft. What counts as a locus and as an allele differs
by track:
| Free operator | Shader track | UI panel track |
|---|---|---|
splice | Function definitions present in both parents, matched by name and by argument count, excluding main() and excluding bodies identical up to whitespace. If the per-locus roll selects nothing, one candidate is forced, so the operator never returns the parent unchanged. | Declaration blocks inside the <style> element, paired across parents by the overlap of the property names they set, with a minimum overlap of 0.4. The first parent’s selector is kept and the donor’s body is substituted. |
graft | A function the second parent defines that the first does not, main() excluded, inserted ahead of the first parent’s first function so the definition precedes any use. | Undefined for the track. Every graft roll on a UI panel falls through to jitter. |
jitter | Float literals only; integer literals and array subscripts are left alone. Each selected literal is scaled by a factor drawn around 1 by up to the strength, and a literal of zero is replaced by an absolute value between -0.5 and 0.5. | Lengths in px, rem, em and % are scaled the same way, and hex colours are converted to HSL and moved: hue by up to 40 degrees either way, saturation by a factor between 0.6 and 1.4, lightness by a factor between 0.75 and 1.25. |
A structural operator is often inapplicable, since two parents may share no swappable locus and a
panel may hold too few rules to pair. Rather than lose the pass, the code retries with jitter, and
abandons the birth only if jitter also finds no allele to move. A free operator consults no
prompt gene: its child keeps the first parent’s directive and the
first parent’s title.
A model operator selects a living prompt gene for the track first, and abandons the birth if the
track has none. The prompt sent to the model is the track’s fixed contract,
then the directive, then the parents’ full source. The axes a mutate or crossover must move along
are drawn at random from a fixed list of fourteen per track. fresh is additionally handed short
labels for up to fourteen of the pool’s current organisms, ordered by fitness, and told that a
near-duplicate of any of them is worthless.
The model runs as one headless turn with no tools available to it. The reply’s last fenced code
block becomes the genome; a leading TITLE: line, if present, becomes the title, truncated to 60
characters. A call that fails or exceeds the configured timeout is logged as a failed birth and the
pass produces nothing.
Radical mutation
A mutate roll has a second roll inside it. On a probability held in lab.config.json, doubled
while the track is in a diversity crisis, the operator becomes a
radical mutation: the model is told to keep only the single element it considers the parent’s
best idea, rebuild everything else around it, move to the opposite end of three axes rather than two,
and produce something that could not be confused with the parent at a glance. Like fresh, a radical
mutation receives the pool labels to avoid, so the jump lands away from occupied territory.
A radical child is recorded under the operator name radical, not mutate, so the branch is visible
in the birth record afterwards.
Inheritance
| Property | Child’s value |
|---|---|
| Rating | The mean of the parents’ owner ratings. A fresh organism starts at the configured Elo midpoint. |
| Generation | One above the highest parent generation. A fresh organism is generation 0. |
| Lineage | The parent ids, in order, first parent first. Phylum is derived by walking the first parent back to its fresh ancestor. |
| Directive | A model operator’s child is attributed to the gene that produced it, and that gene’s use count rises. A free operator’s child carries the first parent’s gene. |
| Title | The model’s TITLE line, or the first parent’s title for a free operator. |
| Render status | Not inherited. Every organism is born unrendered and unjudged, with no games on either ladder. |
Inheriting the parents’ rating rather than starting at the midpoint means a child is not made to re-earn its lineage’s standing from zero, and it means an unjudged child is ranked at its parents’ level until judging moves it.
Rejection at birth
A candidate genome is discarded, with the reason logged, on any of these:
- It fails the track’s contract.
- Its code is byte-identical to a parent’s. A free operator produces this whenever the jitter lands on nothing that matters.
- It came from
freshand sits within the minimum fresh distance of some organism already in the pool. - It came from a model operator and sits within the minimum child distance of one of its parents.
- It would join a clone family already at its cap.
Free operators are exempt from the parent-distance test. Token distance ignores numeric literals, so a jittered child measures zero from its parent by construction and the test would reject every one of them; the clone family cap still applies.
The breeding loop
The daemon runs one pass over the configured tracks in order, then sleeps. Within a pass, each track is handled in sequence:
- Culling runs, so the gate below reads the pool that culling leaves behind.
- The living organisms in the track with no game on either ladder are counted. At or above the configured backlog limit, the track is skipped for this pass.
- One birth is attempted. Culling runs again.
- Prompt evolution runs for the track when the shared birth counter reaches its next threshold, on the cadence prompt genes sets out.
Breeding never halts on population size. The only thing that stops it is the judging backlog, since death rather than a pause in births is what holds the pool at its carrying capacity.
The pass sleeps 400 ms when any track recorded a birth and the configured idle interval when none did. Free operators return in milliseconds, and a full idle sleep after one would spend the entire speed advantage of not having called a model.
Bound to
The source this page's claims were read against, named by symbol and pinned by the digest of the file it lives in.
| Symbol | Digest |
|---|---|
| ask | b7d1d0c7aa85 |
| birth | b72f4e12e72f |
| birthPrompt | 979ad190a564 |
| lab.config.json | a095dd3b3dab |
| OPERATORS | 2135902ed4dc |
| phylumOf | 193eb96a460a |
What links here
- Crossing sends readers here
- Death sends readers here
- Diversity sends readers here
- Freezing and reseeding sends readers here
- Organisms sends readers here
- Prompt genes sends readers here
- Selection sends readers here
- Taxonomy sends readers here
- The contract sends readers here
- The Rorschach Lab sends readers here
Near this subject
These are the subjects this one is joined to in the field. Step out of this card and they are the wells around the one you are standing in.
- Crossing that page sends you here
- Diversity each sends you to the other
- Death each sends you to the other
- Organisms each sends you to the other
- Prompt genes each sends you to the other
- Freezing and reseeding that page sends you here
- The contract each sends you to the other
- Taxonomy each sends you to the other
- Selection each sends you to the other
- The Rorschach Lab each sends you to the other