robo_genome (faber_tweann v2.4.0)
View SourceRobo Rumble: a genome on the wire, and the limits a host enforces on one.
THIS EXISTS SO A TANK CAN FIGHT ON A STRANGER'S MACHINE. That is the whole goal, and every decision below is answerable to it. A genome has to survive being written down, sent, received by somebody who did not make it, and checked before it is allowed to run.
BUILD, NOT CLAIM. Nothing here tests a hypothesis about the world, so it gets tests and a commit rather than a pre-registration and a gate.
THE FORMAT IS ALMOST FREE, and that is a consequence of an earlier decision rather than luck. A genome is a topology and a flat list of integers:
{Layers, Weights} Layers :: [pos_integer()], the layer widths in order Weights :: [integer()], bias-then-weights per neuron, neurons in order, layers in order
No floats and no maps anywhere in it. That matters because term_to_binary is NOT canonical for maps: this front was already bitten once when a golden match vector hashed a map and produced different bytes in two processes. Over tuples and integer lists it is canonical, so packing is one call and the content hash is stable.
WHY VALIDATE RATHER THAN CLAMP. robo_net:quantize/1 clips a weight into range silently, which is right for an optimiser proposing its own candidates and WRONG for a stranger's genome: clipping changes the genome, which changes what actually fought, which means the published id no longer identifies the thing that ran. So a foreign genome is REJECTED rather than repaired, and the id a host publishes is always the id of the code it executed.
THE LIMITS ARE A DENIAL-OF-SERVICE DEFENCE, not a quality bar. PLAN_ROBO_RUMBLE section 8 has listed them as owed since phase 0, with the reason: "without these a visitor denial-of-services a host with a pathological topology". A host runs a stranger's network up to MAX_TURNS times per tank per battle, so the cost of a battle is linear in the weight count. Nothing here judges whether a genome is any good; that is what the battle is for.