What generation 3 changed, what the runs say, and what is still open. The instrument is here, and every claim below that names a cell links into it. This page carries no controls and computes nothing: it is the commentary that used to sit between a reader and the instrument. Frozen with it: generation 4's instrument is /hutter/pprog/p8v2-gen4-e64/.
Nothing here is a pick. Four variants were run; the choices are
the programmer's (#variant_protocol),
and this page is evidence put in front of that judgement.
MJC's answer on axis A was a5 — "each pattern fires at a rate set by its own support" — together with a ruling that removes the ground the previous rule stood on: "There is no constant sum ever in an ES. The only thing constant is total probability = 1 and that is after softmax." A2's decay of 2 was derived from a constant-sum invariant, so it keeps its measurements and loses its justification. Three alternatives were built against the answer, and none of them is a pick:
| rule | what it does | what to watch |
|---|---|---|
| A4 | accumulate, then decay by the support deficit of the strongest evidence that arrived: smax − s. | the deficit is the same for all 256 entries of a position, so it moves the whole vector together. |
| A5 | no decay at all. A pattern of support s is applied only on time steps that are multiples of 2smax−s, so the rate is the fall-off. | the only rule where the rate differs between the patterns feeding one position. Step A5 and watch applications switch off and on. |
| A6 | accumulate, then decay by the number of applications that actually arrived instead of the constant 2. | the minimal change that drops the withdrawn argument while keeping its counting. |
#f-p8 is explicit that
applying a pattern always costs energy. So the count is an implementation that does not
yet mean what the alternative says, and it does not touch the settling numbers, which
are what the axis is read on.
conv records the
first time step after which the window's argmax sequence stops changing. Under a
scheduled rule the low-support patterns have not fired yet at step 1, so a window can
look settled because nothing has happened. The column measures the wrong
thing for a rule that fires on a schedule, and generation 3 records that rather than
correcting it silently. Select any position under A5 and step: the panel shows the
applications sitting out the steps their period does not divide.
A4 and A5 need each pattern's own support. For a k=1 pattern that is
c1[x × 256 + argmax], a value in the 65536-byte learned count
matrix — and that matrix is not in a generation-3 model.
#f-p8-deficit says so directly: support is read from the learned tables,
"which under B1 are in memory but NOT in the model file". A page that ran the rule
from a generation-3 model alone would be inventing the numbers.
It is recoverable exactly, and the recovery is checked rather than assumed.
Generation 2's v013 stores that matrix, and axis A changes only settling,
so v013's learned model either is or is not these variants' learned
model. The builder compares the k=1 table and the token section byte for byte
and refuses to build if they differ. They do not differ, so the matrix is theirs and
this page uses it. Borrowing across a different learned model is exactly what the
generation-2 page refuses for B2, and the same test decides both.
Two things fall out of it that are worth seeing rather than being told. The
reference support smax at this sample is 2 — the largest learned weight
over the k=1 argmax pairs and over the kept k=2 rules, floored at 1, which is what the
runs used (confirmed by cmpr-src 2026-08-11: 2 at e64, 6 at e1k, 9 at e10k). So the
whole axis has three rates here — every time step, every second, every fourth
— because every support in the model is 0, 1 or 2. And which reading of
smax should win is still an open
choice, so it is a control on this page rather than a constant: an open
sub-parameter earns one for the same reason an open axis does. The setting marked
in model is the one the runs used.
c1[x×256 + argmax]
— not the 255 the settling shell delivers it at. So under A4 and A5 the same
pattern delivers at 255 and is rated at 0, 1 or 2 in the same time step: it
arrives as an absolute rule and is charged a fall-off as though it had been seen once
or not at all. Open any forward application under A4 and the panel shows both numbers
on the same line, because they are both true of it.
#f-p8-period named that as a
possibility when it was written; at e10k it is what happens. So the rule you can drive
comfortably on this page behaves qualitatively differently at the sizes that matter,
and this page cannot show you that: it is one sample. Measured in
the generation 3 report.
m names e. Expand it: m occurs at
positions 1, 12, 29, 44 and 61 of this sample, followed by e twice and
l three times. The rule the model kept is the less frequent of
the two, in the only data there is. It is not a tie and not a tie-break: the stored
counts are c1[m][e] = 2 and c1[m][l] = 1, so the log
estimate inverted the order of a 3-count and a 2-count — the uncorrelated-error
property LSA is designed around, seen from the data side. It bears directly on axis A,
because a5 sets a pattern's rate from a support whose ordering is unreliable
at these sample sizes. Open it: position 2, settled, or the pattern itself, with its concordance.
#pp_settle the forward k=1 application is one line —
fwd[table[a]] = wsrc; — with no attenuation term at all. There is no
255 in the C. 255 is what the absence of the term amounts to, because 255 is
min's identity on a byte, and the block says so in as many words: "its
pattern weight is the absolute 255, so under the frozen message rule the message is the
source's own activation on that one byte". Three lines below it the k=2 token does write
its min: msg = (tok_w[ctx] < gate) ? tok_w[ctx] : gate. So the shell's
255 is a structural claim about the pattern, made by omission. The query layer's
1 is a bare literal, pq_atom(a, c, 1), sitting between a literal 255 for the
memory chain and the model's own stored byte for the k=2 rules. Only one of the two has
an argument behind it.
settle_window. Under B1 the
baseline's body opens with (void)c1;, and the spec block instructs it: "the
parameters c1 and have_lpp are unused in this alternative and must not be referenced".
So c1[a×256 + table[a]], the exact learned support of the rule about to
fire, is in scope at the call site and deliberately dropped. What makes that defensible
rather than an oversight is axis B and the decoder: under B1 the model file carries
the argmax table and nothing else, so a decode-time settling pass has no matrix to
attenuate from. Attenuating in the compressor and not in the decompressor would make the
two disagree. The pass-through is the only rule that is symmetric across the model
boundary — which is exactly the coupling p8v2-words.md names under
"where support comes from at decode time", and it makes the k=1 strength an
axis-B question rather than a constant anybody is free to change.
sup1[x] = c1[x×256 + table[x]] to set each pattern's fall-off
rate, and then apply the forward message with the same unattenuated
fwd[table[a]] = wsrc. The identical number decides how fast the pattern
decays and is ignored when deciding what it delivers. That is what the instrument shows
as delivered at 255, rated at 0, 1 or 2, and it is in the generated C rather than
inferred from the viewer.
fwd[c] = lsa_min(c1[a×256+c], wsrc) over the whole row: the stored
65536-byte LPP carries 41 entries at strength 1 and 6 at 2, the same support the query
layer reports. So the same pattern is absolute under B1 and support-1 under B2
— a difference in what the pattern says, not in how it was obtained, on an axis
whose description is reconstruct-versus-store.
../cmpr-src's, in
whichever direction it decides, and the two ends are not equally arbitrary. It reports
both on every forward application rather than quietly printing the one that agrees with
what the engine did. The k=2 token strengths have no such gap: the model stores them, the
query layer reports them, and the shell applies them, and all three agree.
#p8v2_gen3, the push that opened the
generation, with the programmer's answers inline.#p8v2_latd_probability_ask_20260815
— the four questions the instrument page asks and does not answer.Published under #viz_standard. Regenerated by
docs/pprog/build-p8v2-gen3-e64 from
docs/pprog/p8v2-gen3-e64-notes.tpl.html, never hand-edited.