/* #p8v2_gen3_viz_goal_20260810 @viz_standard @viz_surfaces @p8v2_e64_viewer_goal_20260805 @root GOAL: the gen3 settling instrument -- f in one place, SN in, LATD out Written 2026-08-10 in answer to #p8v2_gen3 (../cmpr-src), MJC's push opening generation 3. That document is written mainly against the viewer at /hutter/pprog/p8v2-e64/, so most of what it asks for is OURS. This block is the whole of our part; it is a spec, not a build. Read #p8v2_gen3 too -- it is one screen and it is the source -- but nothing below depends on having read it. ## The division, so that this block does not overstep Generation 3's design questions -- what f becomes, what the real A2 firing rule is, whether settling extends to several windows -- are the programmer's, and per #variant_protocol the axes/choices block for the generation is written on cmpr-src's side and AGENTS DO NOT PRUNE. Two things follow and both matter here: - #variant_protocol makes visualization a deliverable of every generation, and says most of the documentation of what the axes are should come THROUGH the visualizations. Generation 3 leans on that harder than 1 or 2 did: gen3 says "This is what we want to be able to play with in the visualizer" and closes with "If all of this is in the viewer, then we have what I want". The viewer is where this generation's rule gets designed, not where it gets reported afterwards. - So we build the instrument that makes the rule drivable, and we do not pick the rule. Anything driven that was never run stays fenced (below, item 6). ## State, 2026-08-10, SECOND PASS -- READ THIS BEFORE THE ITEMS MJC ANSWERED THE CHOICES IN #p8v2_gen3 AFTER THIS BLOCK WAS FIRST WRITTEN, and cmpr-src then built generation 3 against those answers. The answers that move our work: G = g2 a NEW generation-3 page; p8v2-e64 is frozen as the generation-2 record. See "The surface" below, which is rewritten. He also asked us to establish a lightweight versioning convention for viewers, which is now a section of #viz_standard. A = a5 each pattern fires at a rate set by its own SUPPORT. And, killing the derivation the built A2 rests on: "There is no constant sum ever in an ES. The only thing constant is total probability = 1 and that is after softmax." Three alternatives are BUILT and RUN (A4 attenuate by the support deficit, A5 schedule by the support, A6 decay by the number of applications that arrived) -- so item 6's "parameterised family so the rule can be driven before it is implemented" is overtaken in its premise: the rules now exist and what the page owes is CONTROLS for them, per the every-axis-gets-a-control convention. B = b1 min(w_p, w_s) stays frozen and is now stated normatively in #f-p8. F = all the fold-back landed. #f-p8 IS the single normative statement of f and carries the application rule, W and its non-overlapping tiling, the W time steps, initialisation, clamping, and the argmax tie-break. FIVE OF THOSE ARE MARKED AXIS CANDIDATE at MJC's request -- "these choices should get ramified through the visualization layer as variants" -- so the page's job grows from three settling controls to those as well. E --latd is BUILT in the query layer. Given a pattern it answers with the input positions that formed it, as SN clusters with observed successor counts. MJC on presentation: "presented by viz layer as SN ... Could also be presented very nicely e.g. concordance-style or other NLP viz conventions; also left up to Claude for a first pass." That is a free hand and it is ours. D parked pending the viewer. The eventual shape is "not a sliding window at all, but a sequence of windows, once each one settles, then the next one comes up", with cross-window settling as a decode-cost-against-rate tunable. AND MJC'S OWN SPEC FOR THE PANEL, in #p8v2_gen3 step 4, which supersedes item 1's wording: "A panel that IS f: for one position and one time step, every pattern application in SN with its arithmetic, in order, ending in the new activation vector." BUILT, AND THE GENERATION IS SERVED. Four items landed in what is now the frozen p8v2-e64 -- 2 (SN), 3 (the LSA operations table), 5 (LATD) and 7 (the "message" rename) -- and they stay there because they correct what that page says about generation 2. The generation-3 instrument is docs/pprog/p8v2-gen3-e64/, built 2026-08-10 from docs/pprog/build-p8v2-gen3-e64 and p8v2-gen3-e64.tpl.html, and it carries all seven items plus the three new rules. Also done: the generation-3 panel's linking, the versioning convention, and the entry-point link in progress.html. WHAT IS LEFT is not on this list any more. It is the generation's own open choices, which are MJC's and not ours (#pprog_p8v2_gen3_goal_20260810, seven of them), and the two upstream catch-ups recorded under "Concessions" below. ## What the generation-3 instrument does, beyond the seven items THE PANEL THAT IS f, which is MJC's step 4 verbatim. Select a position, step to a time step, and the page writes out that one application of the total visible pattern: each pattern application in the order the update consumes it, with the SN atom that fired, the arithmetic that produced its entry, the support that sets its rate, and the input positions it records; then the combination, which is the axis; then the new activation vector, DRAWN as a profile rather than listed. That is what replaced the 1351-line JSON dump, and axes.json's worked examples are now links that drive the page to the position and step they are about. THREE NEW RULES, DRIVABLE. A4 attenuates by the support deficit, A5 schedules by the support, A6 decays by the number of applications that arrived; implemented from #f-p8-deficit, #f-p8-period and #f-p8-indegree, with A5's schedule taken from the compressor's own 1-based step counter. NOTHING ON THE AXIS IS CONFORMANCE-CHECKABLE, because all three accumulate with LSA addition and that draws from a stream this page cannot replay. What CAN still be compared is settled_ok, a count rather than a state, and it matches the runs exactly for all three new rules: v021 17/17, v022 17/17, v023 19/19, with the baseline at 19/20. The page shows that comparison and labels it as the weaker evidence it is. ## Concessions, both upstream, both worked around rather than hidden THE SUPPORT IS NOT IN A GENERATION-3 MODEL. A4 and A5 need each pattern's own support, which for a k=1 pattern lives in the 65536-byte learned count matrix; #f-p8-deficit says plainly that it is "in memory but NOT in the model file". Recovered by borrowing generation 2's v013, which stores it -- and legitimate only because the builder compares the k=1 table and token section BYTE FOR BYTE and refuses to build if they differ. It is the same test that makes the generation-2 page refuse to borrow a stored LPP across a different learned model. Two things fall out and both are on the page: smax is 2 at this sample, so the whole axis has three rates -- every step, every second, every fourth -- and which reading of smax the runs used is an open choice, so it is a CONTROL rather than a constant. axes.json HAS CAUGHT UP ONCE OF TWICE, 2026-08-11. The generation field now says 3 and the file carries a `generations` list of every generation it describes, which is a better shape than the equality we asked for -- see the next paragraph for why. settling_columns.numbers STILL has no generation-3 rows, so the diagnostics are still read from gen3.tsv; that workaround stays, with its note in the builder. AND THE FREEZE DREW BLOOD THE FIRST TIME IT WAS TESTED. When axes.json moved to generation 3, the FROZEN generation-2 page STOPPED BUILDING: its builder asserted that the file's generation field equalled 2, and the file is a living document that always describes the newest generation. That is "frozen must not mean unmaintainable" failing within a day of being written down. The shape of the problem is general -- a frozen page renders an old generation out of a file that keeps moving -- and the fix is upstream's `generations` list: both builders now check that the generation they render is one the file DESCRIBES, not one it currently IS. Anyone freezing a future page inherits this: check membership, never equality, against anything generated that outlives your page. ## What cmpr-src answered, 2026-08-11, and what it changed here THE THREE OPEN QUESTIONS CAME BACK, and the implementation was right on both counts it could have been wrong on. smax as built is the largest learned weight over the k=1 argmax pairs and over the kept k=2 rules, floored at 1 -- exactly what this builder computes -- and it is 2 at e64, 6 at e1k, 9 at e10k. The runs used it. The smax control stays anyway, because WHICH reading should win is still the generation's open choice B; the setting that ran is now marked as such. THE k=1 GAP BITES INSIDE A4 AND A5, NOT BESIDE THEM, and this is the sharper form of what we raised on 2026-08-10. A k=1 pattern's support is its LEARNED weight, while the shell DELIVERS it at 255. So in one time step the same pattern arrives as an absolute rule and is charged a fall-off as though seen once or never. At e64, 229 of the 256 support entries are 0, so they decay at the maximum rate while delivering at the maximum strength. The f panel now prints both numbers on the same line, because they are both true of it, and the page says whose choice it is to settle (theirs, choice C). A5's PERIODS OUTGROW THE WINDOW AND e64 HIDES IT. The period is 2^(smax - s) against a window of W time steps: at e64 the periods are 1, 2, 4 and everything fires; at e1k they reach 64; at e10k they reach 512 and a support-0 pattern NEVER FIRES INSIDE A WINDOW, for 169 of the 256 bytes. The page says so and says plainly that it cannot show it, being one sample. That is a limit of the instrument and it is stated rather than left to be discovered. A5 IS NOT CHEAPER, AND THEY CORRECTED THEMSELVES ON IT. The 6 percent drop in applications is not the schedule buying energy: the implementation computes all three vectors and counts them BEFORE the period decides, so a skipped application costs what a taken one costs. The drop is indirect. Our numbers table shows the application count, so it now carries a warning beside that cell rather than letting a reader draw the conclusion the report first drew. ON VERSIONING THEY DID NOT OVERRIDE US. The generation-3 goal's choice G now carries both forms -- theirs, and ours with the p8v2-gen1-is-legacy argument stated -- so MJC picks between two positions rather than between a proposal and a silence. Our tree keeps p8v2-gen-/ until he rules. TWO THINGS TO PICK UP THAT ARE NOT IN THE ITEM LIST: THE LSA OPERATIONS TABLE IS NOW DATA. cmpr-src put seven lsa_ops rows into axes.json, lifted from #f-p8, and acceptance-p8v2-axes fails if any lsa_* identifier appears in that file without a row. Our hand-written table in p8v2-e64 was right to exist and is now the wrong mechanism: the gen3 page reads lsa_ops the way it already reads alternative prose, and does not restate it. TWO FINDINGS THE GEN3 PAGE HAS TO SHOW, both from cmpr-src's report: - A UNIFORM FALL-OFF CANNOT REORDER AN EVENT SPACE. lsa_sub is monotone and A2 subtracts the same d from all 256 entries, so a uniform decay can only change the settled argmax by pushing entries onto the 0 floor. A4 and A6 vary d between positions but are still uniform within one, which is why A6 lands within 2 positions of the baseline at e10k while decaying half again as fast. A5 is the only one where the rate differs between the patterns FEEDING ONE POSITION, and it moved the most. The rule has to bite between the patterns feeding a position, not between positions. - THE MODEL NAMES THE WRONG SUCCESSOR, which is the LATD case we raised, sharpened. In the sample 'm' is followed by 'l' three times and 'e' twice, and k1['m'] = 'e'. From v013's stored matrix the learned weights are c1[m][e] = 2 and c1[m][l] = 1: LSA's stochastic increment took a 3-count to 1 and a 2-count to 2. Not a tie and not a tie-break -- the log estimate inverting the order of two small counts. It bears on a5, whose rate is set by a support whose ORDERING is unreliable at these sample sizes. AND A CAVEAT THAT MUST BE ON THE PAGE, not discovered: A5's mean time steps at e64 is 1.00 and that is NOT convergence. conv records the first step at which the argmax sequence stops changing, and under a schedule 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 scheduled rule. AND ITEM 2 PAID FOR ITSELF ON THE FIRST DAY, which is the argument for its ordering better than the argument below. Putting SN and LATD on the page together produced a finding neither would have produced alone, recorded on the page as "One pattern, two strengths" and raised with cmpr-src: THE k=1 SECTION STORES NO WEIGHT -- it is 256 bytes of argmax and nothing else -- so its two readers supply opposite ends of the scale. The query layer reports every k=1 pattern at strength 1 (all 256, in all ten generation-2 models). The settling shell applies them at 255: a forward application under B1 is min(255, w_s). On a log-support scale 1 says seen once and 255 says an absolute rule, which is exactly the pair of extremes #p8v2_gen3 names. IT IS ALSO AN UNNAMED PART OF AXIS B. v013's stored 65536-byte LPP carries 41 entries at 1 and 6 at 2, the support the query layer reports, while B1 reconstructs the same direction and applies it at 255. 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. THE WORKED CASE, which is LATD doing the work it was put there to do: k1['m'] = 'e', applied as an absolute rule; 'm' occurs at positions 1, 12, 29, 44 and 61 of the sample and is followed by e, l, e, l, l. Checked against the raw prefix. The model asserts as certain a thing that holds twice in five times in the only data there is. OURS WAS TO REPORT IT, NOT TO RESOLVE IT. The page prints BOTH strengths on every forward application rather than the one that agrees with what the engine did, and says the fix is cmpr-src's in whichever direction they take it. The k=2 tokens have no such gap -- model, query layer and shell agree at 1 and 2 -- and the page says so, because a gap is only legible next to something that does not have it. ## The surface OVERTAKEN 2026-08-10, AND THE REASONING BELOW WAS WRONG. This block said EXTEND docs/pprog/p8v2-e64/ and DO NOT MINT A NEW PAGE, on the argument that a second page would split the settling story in two. MJC answered choice G of #p8v2_gen3 with g2: A NEW GENERATION-3 PAGE, and p8v2-e64 KEPT AS THE GENERATION-2 RECORD. The old argument had not accounted for what rebuilding in place costs -- the generation-1 e64 page was rebuilt for generation 2 and no longer exists to be compared with, which is the loss the ruling prevents. Rebuilding in place is not a version. So the surface is now TWO surfaces: docs/pprog/p8v2-e64/ FROZEN as the generation-2 record. It gains a banner naming its generation and linking its successor, and nothing else. The gen3 items already built in it (SN, LATD, the LSA operations table, the "message" rename) stay -- they are corrections to what it says about generation 2, not generation-3 content. docs/pprog/p8v2-gen3-e64/ THE GENERATION-3 INSTRUMENT, to build. Naming follows the convention MJC asked us to establish, now a section of #viz_standard: the generation is the version, panels keep gen.html, instruments are versioned by path as p8v2-gen-/. We did NOT take cmpr-src's proposed /hutter/pprog/p8v2-gen/ because p8v2-gen1/ already exists and is not generation 1's page; see #viz_standard for the full argument. Raised for MJC. docs/pprog/p8v2-gen1/ the panel home. Generation 3's panel RENDERS AND IS LINKED as of 2026-08-10: it rendered automatically and nothing linked it, and gen3.tsv was not beside it, so build-p8v2-gen1 now discovers generations from the posdir names and drives symlinks, panels and navigation off one list. Generation 4 links itself. page docs/pprog/p8v2-e64/index.html self-contained, no fetch, no CDN template docs/pprog/p8v2-e64.tpl.html 894 lines, engine + prose builder docs/pprog/build-p8v2-e64 220 lines; reads ../cmpr-src tests/pprog/ models/p8v2/enwik9/64/, gen2-pos/, axes.json; bakes axes.json into the payload; runs no compression spec so far #p8v2_e64_viewer_goal_20260805 (ours), #hutter_e64_viewer_prereq_20260805 (theirs) The generation panel at /hutter/pprog/p8v2-gen1/ renders one panel per gen-pos directory it finds, so a gen3-pos dump needs no work from us and is not what this goal is about. ## RESTRUCTURED 2026-08-15, and what came off the page is here instead MJC reviewed the built page and the verdict was that it had become an essay with an instrument in it. The general rules are now a section of #viz_standard, "An instrument is not an essay with a widget in it", and they bind every viewer, not this one. What follows is only this page's part. WHAT THE INSTRUMENT GAINED, which is where the effort went: SUPPORT PAINTED OVER THE DATA. Select a position and the applications reaching it are given colours -- forward k=1 blue, backward k=1 orange, the k=2 token green -- and the input positions each was learned from are shaded in that colour on the byte row of the grid. A byte in two support sets is STRIPED in both. That stripe is gap 2 of the probability section made visible: #f-p8's combination rule needs the observation sets disjoint, and every stripe is a byte where they are not. ONE SOURCE FOR THE OVERLAP. The measured sentence in gap 2 first disagreed with the grid -- it said "no position is counted twice" over a grid with a striped cell -- because a 2-token's observation covers TWO bytes and its support set is indexed by one. The sentence now reads the same painted sets the grid does. A pattern's observation is its whole antecedent span; anything that measures overlap has to use the span. THE PANES ARE TABS UNDER THE GRID: f at this position, the patterns, back to the data. They are persistent DOM and not part of the rig's innerHTML, because the rig is rewritten several times a second under the step slider and a table inside that string loses its scroll position and its selection on every step. DEEP LINKS, which is item 4c: #v=&p=&s=&t=, written on every render and read once on load. THE CONCORDANCE READS AS ONE BLOCK. Its columns are exactly as wide as their content, which means single-character headings (# ‹ A S ›) and a legend under the table; a heading reading "followed by" over a one-character column destroys the alignment that makes the mark work. A space is written ␣ in the one-character columns and left as a space in the context columns. DEFAULT VIEW: position 2, settled. Early time steps leave the middle of the window on 0x00 sources whose support sets are empty, so a low default step opens the instrument with nothing painted on it. WHAT LEFT, AND WHERE IT WENT: the discussion sections -> docs/pprog/p8v2-gen3-e64/notes.html, which links back into the instrument by fragment. Two staleness fixes went in on the way: "in all ten models" was generation-2 vintage, and two panels had lost a

opener. the per-variant results table and the settling-column definitions -> DELETED as sections. The numbers are on the preset button that loads the run and the definitions are its tooltip, both still read from axes.json. the control table, the grid legend, the axis definitions, the LSA operations table ->

at the instrument, plus a title on every control. the conformance section, the "which generation is this" box -> Provenance, at the foot. the "no picks / not a result" box -> DELETED. The fencing stays on the figure. WHAT A PATTERN APPLICATION IS -> here, because it was on the page for the agent's benefit and not the reader's. Keep it: ONE LPP's contribution to ONE position from ONE neighbouring source position; three per unclamped position per time step (forward k=1 from the left, backward k=1 from the right, the k=2 token from the two to the left through the AND gate). Each entry is min(w_p, w_s), which IS the inner min of the UM's max-min forward pass f_p(t)_j = max_i min(t_i, p_ij), with the source restricted to its argmax event by the admitted optimization -- exact when the source is absolute, an approximation elsewhere. Under A1 forward and backward are then combined with the outer max, so A1 is the forward pass written out longhand. TWO DEPARTURES, and they are the reason this is worth remembering: a k=2 token application ASSIGNS rather than maxing (#f-p8 argues that is right because k=2 is a subset of k=1 and the two are fully correlated -- and it is also why axis D can remove nothing), and A2 and A3 leave max-min altogether for LSA addition, which is a different f rather than bookkeeping inside the same one. The normative statement is #f-p8; the page cites it and does not restate it. ## The seven things gen3 asks the viewer for Each item gives what gen3 said, what is on the page TODAY (measured 2026-08-10, not remembered), and what to build. ### 1. f described in ONE place, and the page's engine IS that description GEN3: "we want to get back to f described in one place, and each application of patterns via f starting from SN, going into interpretable arithmetic operations". TODAY: f is spread across the JS (the step function, the axis-A branch, the application rule, the detail pane) and described again in three prose sections -- "What a pattern application is", "How to read it", "The axes". A reader assembles the rule from four places and none of them is the one that runs. BUILD: one f PANEL that is simultaneously the definition and the engine, sitting above the strip and showing the rule the page is executing right now under the current control settings, in UM terms: t_{n+1} = p x t_n over the visible P. Every other section cites it instead of restating it. When a control moves, the panel's text moves, so there is no way for the description and the computation to disagree. Vocabulary is already fixed and is not reopened: a TIME STEP IN f, never a sweep; a PATTERN APPLICATION, never a message (#viz_standard). ### 2. Every application starts from SN -- BUILT 2026-08-10 GEN3: "SN means that every pattern is interpretable." TODAY, MEASURED: THE PAGE CONTAINS NO SN AT ALL. `grep -i sn p8v2-e64.tpl.html` finds nothing and the builder never calls the query layer, although #p8v2_e64_viewer_goal_20260805 said the builder would bake it. The detail pane names patterns as byte pairs -- "fwd apply source i at 8 w 1 -> n". THE QUERY LAYER WORKS ON P8V2 MODELS, verified 2026-08-10, so this is unblocked: cd ../cmpr-src && ./cmpr/dist/cmpr --run wordsv2 --ofra tests/pprog/p8v2-words.md \ --patterns --model tests/pprog/models/p8v2/enwik9/64/wordsv2-v002.m BUILD: the builder pulls SN and bakes the atom for every pattern the page can show; the detail pane names the atom that fired. TWO THINGS THAT WILL BITE: - IT IS A DUMP, NOT A SELECTION. v002 at e64 emits 66152 lines -- the whole structural line, the memory chain included. The builder SELECTS by family (memory-chain shifts at 255, the learned k=1 markov, the k=2 token rules) and never bakes the dump. - READ THE DIRECTION RIGHT. In a --patterns dump the UNINDENTED line is the FROM event and the indented line beneath it is the TO event with its strength. This block first recorded the k=1 markov as an upstream SN defect on the strength of reading it the other way round; it is not a defect and the ask was withdrawn the same day. The memory chain settles the direction beyond argument, because only one reading of "The input byte 1 time steps ago was m." "The input byte 2 time steps ago was m." 255. is the shift. So the learned k=1 markov, which prints as "The input byte is <." -> "The input byte is m." 1., says k1['<'] = 'm', and it does: all 27 entries were checked against the model bytes. Both events sit in the input ES with no time offset because F ADVANCES TIME -- every pattern spans one time step, which is the same convention the memory chain is using. The atoms are publishable as they stand. ### 3. No bare implementation identifiers: the LSA operations table -- BUILT 2026-08-10 GEN3: "ordinary arithmetic, or LSA operations if a table is provided on the page that states what those operations are, no more lsa_ceil_log2". TODAY: the detail pane prints "each predecessor paying lsa_ceil_log2 = 3" (template line 645) and the axis-A worked example's formula string names lsa_add, lsa_sub and lsa_sum256. None of the four is defined anywhere on the page. BUILD: an LSA OPERATIONS TABLE on the page: one row per operation that appears anywhere in a reader's path, giving the operation, its meaning in ordinary arithmetic, whether it saturates and at which end, and whether it draws from the entropy stream (which is what makes A2 and A3 unreachable for the conformance check). Every occurrence links to its row. Where the operation is just arithmetic, WRITE THE ARITHMETIC and drop the name. STANDING RULE, which is the general form of gen3's complaint and belongs in the page's own house rules: no identifier from the C reaches the reader without a row in that table. ### 4. The worked example is a JSON dump and must stop being one GEN3: "Mostly what this worked example shows is that we need better visualization; scrolling through a multi-hundred-line JSON object is not what we want." TODAY, MEASURED: axes.json's axis-A worked example -- "A3 renormalisation and A2 decay at the same position and sweep", position 37, step 2 -- is 1351 lines of JSON when stringified; axis B's is 264 and axis C's is 113. Template line 754, function example(), renders any object it does not recognise as
JSON.stringify(v, null, 1)
, under the comment "rendered without inventing a shape for it". That was the right call when the shape was unknown. It is now the thing gen3 is pointing at. BUILD, in order of increasing preference and all three are wanted: a. AN LSA VECTOR IS DRAWN, NOT LISTED. One mark, used everywhere a vector appears: a profile over the 256 events, which at e64 is mostly 1s and 2s with one or two spikes and reads instantly. 256 JSON key/value lines is that same fact, unreadable. b. THE CHAIN IS A STEP-THROUGH, in the operations of item 3: before -> the applications that fired -> accumulated -> the sum -> the excess -> after, each step showing what changed and by how much. This is one worked example of f, so it is rendered by the f panel of item 1, not by a second mechanism. c. BEST: STOP SHIPPING A BAKED EXAMPLE. Drive the LIVE page to variant/position 37/step 2 and let it render, with a deep link (URL fragment carrying variant, position and step) so the cell is citable. axes.json's recorded numbers then become a CONFORMANCE TARGET for that cell instead of the display -- a stronger use of them than printing them. CAVEAT, and it must show in the cell rather than be discovered: both A2 and A3 draw from the shared entropy stream, so a JS recomputation will not reproduce their numbers. This is the same reason the page's existing conformance check reaches only the nine A1 variants. Where the live cell cannot conform, the cell says so. ### 5. LATD: every pattern expands to the input positions it records -- BUILT 2026-08-10, ### EXTENDED TO EVERY PATTERN AND EVERY PREDICTION 2026-08-15 GEN3: "LATD means that every pattern can be expanded to the set of input positions which it records ... we can trace every pattern back to specific input positions which are responsible for it. Then the probability interpretation becomes intuitive to read out." THIS IS THE CENTRAL NEW CAPABILITY, AND e64 IS WHERE IT IS FREE. VERIFIED: the e64 models carry n = M = 64 in their header (wordsv2-v002.m), so THE TRAINING SET IS THE 64 BYTES ALREADY ON SCREEN. Every pattern's support set is exactly recoverable by scanning the baked sample -- no new dump, no upstream change, no approximation: k=1 markov a -> b the positions i with sample[i] = a, and what actually followed at each, which is the whole successor distribution and not only the argmax backward the predecessor set of b, the same way k=2 token (a,b) -> c the positions i with sample[i..i+1] = (a, b) BUILD: selecting a pattern application highlights ITS positions in the 64-position strip and shows the counts. "w1 = 1" becomes "seen once, at position 12"; 255 becomes an absolute rule with its evidence on screen. That IS the microstate reading gen3 asks for -- gen3's point is that unlike statistical mechanics our dataset is small enough to look at every arrangement, and at e64 it is small enough to look at them ALL AT ONCE. AND THE WEIGHTS ARE THE STORY. Measured over v002's e64 dump, the pattern weights are: 255 x 16389 (the memory-chain shifts), 1 x 16680, 2 x 7. Gen3 writes "if the incoming patterns have w=1 on every event, the model is saying that we have seen every possibility happen once" as one end of a range. At e64 IT IS NOT A HYPOTHETICAL, it is what the model says. Put a support/weight view next to the LATD expansion so that is visible rather than inferred. EXTENDED 2026-08-15, AND ITEM 5 IS NOW THE WHOLE OF LATD RATHER THAN ONE POSITION'S WORTH. What was built on 2026-08-10 expanded the three patterns reaching the SELECTED position. MJC's free hand on presentation ("concordance-style or other NLP viz conventions ... left up to Claude for a first pass") is taken in full, and the gen3 page gains three sections: EVERY PATTERN, AND THE DATA UNDER IT (#patterns). All 303 patterns inside the window -- 256 k=1 rules and 47 k=2 tokens -- in one sortable, filterable list, each row carrying the SN antecedent, the byte it keeps, its three disagreeing strengths, how many positions it records and how many of those agree. Selecting one writes a KWIC CONCORDANCE below it -- left context, the antecedent in a fixed column, the byte that ACTUALLY followed, right context -- and lights its positions in the strip. The concordance is the right mark because a support set IS a concordance: five lines of which three disagree is not a fact a weight can carry. FROM A PREDICTION BACK TO THE DATA (#chain). The same expansion run backwards over the whole window: one row per position giving what f settled on, every DISTINCT pattern applied to it over the run, and the union of those patterns' support sets; then the reverse index, the sample shaded by how many of the 64 predictions rest on each input position. That last strip is the one nothing else shows -- the predictions do not partition the data, they share it. THE BACKWARD DIRECTION IS NAMED, NOT MINTED. It appears in the chain table as a reconstruction with its own support set and NOT in the pattern list, because under B1 it is not a stored pattern and the query layer prints no atom for it. A page that invented one would be inventing SN. FOUR MEASURED FACTS CAME OUT OF BUILDING IT, all computed live rather than typed in: - 303 patterns, of which only 74 RECORD A POSITION AT ALL. The k=1 table is dense over 256 bytes; the evidence is not. 229 rows are entries with nothing under them. - 296 of the 303 carry strength 1. #p8v2_gen3 offers "every event at w=1" as one end of a range; at e64 it is not the end of a range, it is the model. - THE m -> e CASE IS SHARPER THAN IT LOOKED AND ALSO SMALLER. Separating the two ways a kept byte can fail its data -- BEATEN outright by another successor, versus TIED at the top so the keep is a tie-break -- gives 2 beaten and 10 tie-only. Collapsing them (the first cut of this work did) reports 3 and overstates the first at the expense of a finding that is really about sample size. Both counts are on the page and both are named. - Every prediction rests on 6.6 input positions on average, 57 distinct positions carry all 64 predictions, and the most-used position carries 23 of them. THE SCAN IS NOW PROVED AGAINST THE QUERY LAYER. #viz_standard says a builder IMPORTS the upstream derivation rather than reimplementing it, and the page reimplements LATD in JS because the expansion has to follow the selection. The resolution is to reimplement AND CHECK: build-p8v2-gen3-e64 runs `cmpr --run wordsv2 --latd` for all 303 patterns and compares positions and successor counts against the same scan the JS does, failing the build on a disagreement. It costs 1.3 s. It found one real bug on the first run -- the check compared PRINTED NAMES, and the query layer writes a space as 0x20 -- which is the general lesson: compare byte values, and reuse the reader that already exists (bytes_in) rather than reconstructing a naming convention in a second place. AND THE MATH SECTION, WHICH IS AN ASK AND NOT AN ANSWER. #p8v2_gen3 item 5 ends "Then the probability interpretation becomes intuitive to read out", and reading it out is the step with no document behind it. The page now carries "Is any of this probability?": the four links of the chain that ARE justified with the passage that justifies each (#f-p8's sufficient-statistic definition and its softmax result, LSA.md on what a log count is, and #f-p8's combination rule WITH the disjointness condition attached), and then four fenced panels for what is not covered. The fourth of those is the one the concordance made askable: THE THREE PATTERNS MEETING AT A POSITION ARE NOT DISJOINT, the page measures the overlap live for the selected position, and lsa_add is addition in the count domain, so shared observations are counted once per pattern that saw them. Written up as #p8v2_latd_probability_ask_20260815 and published beside the page. WE DID NOT DERIVE ANYTHING: the derivation is the programmer's, and inventing one on the viewer is the same failure as rendering a rule that was never run. When the document exists the section renders it instead of asking for it. SCOPE FENCE: do not extend the scan to e1k or e10k. There M > 64, the sample is only partly on the page, and a scan would be reconstructing what the query layer should answer. If LATD is wanted at those sizes it is an upstream ask (supporting positions from --patterns), not a scan, and it is not needed for this goal. ### 6. The A axis, relabelled for gen3, and a real A2 to drive GEN3'S RULINGS, verbatim in substance: A1 "isn't what we want, so that's gone" but is "still interesting as a use case for visualization"; A3 "was not anything that I wanted"; A2 "is the promising direction", and the implemented A2 -- subtract 2 from every event -- "is not what we meant, but it's something". The rule gen3 actually describes: inputs arrive from each pattern length at a rate f; how far a signal falls off depends not only on pattern length but on THE ACTIVATIONS OF THE ANTECEDENTS AND THE STRENGTHS OF THE PATTERNS; the left and right event spaces are event spaces, so each has total probability 1, and whatever distribution they carry under the patterns in each direction is what determines the correct fall-off. Its two ends are named: every event at w=1 (we have seen every possibility once) and a w=255 antecedent (an absolute rule from an absolute event); and the case "one event at 255 and all others at 1 or 2, so only the one event fires". OUR PART IS NOT TO DESIGN THE RULE. It is to make it drivable before it is implemented: - KEEP A1 AND A3 AS CONTROLS, each carrying its gen3 status ON the control. A1 in particular is explicitly retained as a visualization case, so removing it would delete the thing gen3 says is still worth looking at. - MAKE AXIS A A PARAMETERISED FAMILY, not three buttons. Expose the fall-off as a rule with knobs, driven by the source event space's distribution and the pattern weight, with "constant 2" as one setting -- so the built A2 is a point in the family and stays exactly reproducible, and the rule gen3 is reaching for is a neighbouring point that can be walked to. - SHOW THE ENDS. The two extremes above are the ends of that knob, and item 5 now sources them from real positions instead of asserting them. FENCING IS WHAT MAKES THIS LEGITIMATE. Every combination that was never run takes the page's existing dashed/warning treatment and its "not a measurement" label; the page already does this and it must not be weakened to make the new controls look better. #hutter_publication_handoff's standing line stays: no picks, no chart point, no compression number. When cmpr-src implements a rule from the family, the page gains a preset and a conformance row and nothing else changes -- which is the test that the family was built the right way round. ### 7. "Message" is back on the page, through axes.json GEN3, first bullet under A: "still using the message terminology which we do not use". TODAY, MEASURED: the template's own prose is clean -- one occurrence, in a JS comment. THE BUILT PAGE HAS 57, because the builder bakes axes.json into the payload and the axis sections render its prose verbatim (deliberately: "lifted from each alternative's block in p8v2-words.md and not paraphrased"). axes.json contains 56 occurrences. #viz_standard is explicit that where the generating side keeps the old word, ours change anyway. TWO WAYS, AND THEY ARE NOT EQUAL. PREFERRED: ask cmpr-src to fix axes.json and p8v2-words.md, since that file is the design document and one fix serves the generation panel too. FALLBACK, if it is not fixed in time: render the lifted prose as an explicit QUOTATION with a translation note, so the page is visibly quoting rather than speaking. DO NOT rewrite quoted upstream prose in place -- that forks a file we do not own, which is precisely the failure #viz_surfaces records for gen1-viz.py. ## Two smaller things gen3 raises that land on the page THE C AXIS. Gen3: token_and-min "makes sense but somewhat ignores the rest of each ES; whether this is handled by decay is an open question", and C2 "is definitely wrong because it drops weak signals and therefore can't support settling". The first is the ADMITTED ARGMAX-ONLY OPTIMIZATION, which #p8v2_e64_viewer_goal_20260805 already required the detail pane to unfold by naming the source event; gen3 raises the price of not having done it. Show, for the selected application, the FULL source event space against the single argmax event actually used -- the gap between them IS "the rest of each ES". And make C2's weak-signal loss visible BY DRIVING IT, the same trick as the application rule's collapse, which that goal block calls the single most valuable thing the page can show. THE D AXIS AND MORE THAN ONE WINDOW. Gen3's answer on D is radical and is cmpr-src's: settling extends to multiple indeterminacy windows, becoming a tunable that trades decode cost against rate. Gen3 also says progress there is blocked on everything above. OUR CONSTRAINT IS ONLY THIS: stop assuming one window. At e64 there is exactly one (W = 64 = the whole sample) and the page is built around that. Do not build multi-window support and do not foreclose it. ## Two defects to fix while in there, unrelated to gen3 - Template line 635: step 0's detail still says every unclamped position starts "on the k=0 background (provisional)". The k=0 background was removed on 2026-08-06; line 293 and the prose at line 189 already say there is none. The detail pane contradicts its own page. - #root's entry for #p8v2_e64_viewer_goal_20260805 still reads "GOAL, not built ... BLOCKED on two cmpr-src prerequisites". It was built on 2026-08-05 and both prerequisites were resolved. Fix that line when this lands, and add this block beside it. ## Order of work SN (2) and LATD (5) FIRST. Everything else reads better once a pattern can name itself and expand to the positions that made it: the operations table has something to annotate, the worked example has a subject, and the A-axis extremes have evidence instead of assertion. Then the operations table (3) and the f panel (1), which together are the "f in one place" that gen3 asks for. Then the axis-A family (6). Then retire the JSON worked example (4), last, because c. depends on the deep link and on the f panel already rendering the chain. Item 7 is independent and should be raised upstream on day one so it has time to come back. ## Asks for ../cmpr-src, ordered by whether we are blocked NOT BLOCKED, but wanted: axes.json and p8v2-words.md say "message" 56 times (item 7). WITHDRAWN 2026-08-10: the SN atom for the learned k=1 markov. Raised as an upstream defect and withdrawn the same day; the atom is correct and the misreading was ours (item 2, "read the direction right"). NOT NEEDED HERE: supporting positions from --patterns, which is what LATD beyond e64 would need (item 5). Raise only if e1k/e10k LATD is actually wanted. WHEN GEN3 RUNS: a gen3-pos dump. The generation panel picks it up with no change on our side (#viz_surfaces). ## Out of scope - Picking any axis, on any generation. #variant_protocol: agents do not prune. - Designing f. The viewer proposes; the rule is the programmer's. - Editing anything in ../cmpr-src. We ask. - A new page, other samples than e64, multi-window settling. - Any chart point, ranking, or number presented as a compression result. - Re-rendering the generation panel. ## Done when The page describes f in one place and that description is the engine; every pattern the page shows names itself in SN; every LSA operation a reader meets has a row in a table on the page and no bare C identifier is left; selecting a pattern application highlights the input positions that support it, with counts, and the weight distribution is visible; axis A is a parameterised family whose settings include the built A2 exactly, with A1 and A3 kept and labelled with their gen3 status, and everything unrun still fenced; the axis-A worked example is rendered by the live page at a deep link rather than dumped as JSON, with axes.json's numbers used as a conformance target and non-conformance stated in the cell; the full source event space is shown against the argmax actually used; "message" no longer appears in the published page; and it is all rebuilt by build-p8v2-e64 rather than hand-edited. Wants: "We want f described in one place, and that place to be what runs" 255. "We want every pattern to name itself in SN, since that is what makes it interpretable" 255. "We want every pattern expanded to the input positions it records" 255. "We want the probability reading to come from positions we can see, not from a softmax" 255. "We want the settling rule drivable before it is implemented" 255. "We want no bare implementation identifiers in a reader's path" 255. "We want the worked example rendered, not dumped as JSON" 255. "We want the rest of each ES visible against the argmax the optimization used" 200. "We want the word message off our page" 200. "We do not want the viewer to assume there is only one window" 200. */