<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>disturbed-circles</title>
    <subtitle>Personal &#x2F; project blog</subtitle>
    <link rel="self" type="application/atom+xml" href="https://disturbed-circles.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://disturbed-circles.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-08-28T00:00:00+00:00</updated>
    <id>https://disturbed-circles.com/atom.xml</id>
    <entry xml:lang="en">
        <title>28-AUG-2026</title>
        <published>2026-08-28T00:00:00+00:00</published>
        <updated>2026-08-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/uruk-hai/28-aug-2026/"/>
        <id>https://disturbed-circles.com/log/uruk-hai/28-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/uruk-hai/28-aug-2026/">&lt;h1 id=&quot;28-aug-2026&quot;&gt;28-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1900&quot;&gt;1900&lt;&#x2F;h2&gt;
&lt;p&gt;I’m in the ‘time to split the monolith up’ stage of this. Some interesting datapoints.&lt;&#x2F;p&gt;
&lt;p&gt;First, I’m roughly 2:1 lines-of-test to lines-of-code. Part of this is double-specification, the Cuke spec covers all
the SRD content, and I have similar cukes for some of the PHB content I’m interested in testing (more on that in a
minute). The agents also write tests, and they also frequently are made to chase mutants and coverage. This results in a
pretty sizable codebase. The whole subproject is about 100KLOC and only about 30KLOC is the actual engine. This is
pretty close to where I likely would’ve landed. If anything, I’d’ve guessed a handbuilt engine would be like, 50KLOC of
engine code and more like 10-20KLOC of tests, so net smaller but probably more mutants and stuff.&lt;&#x2F;p&gt;
&lt;p&gt;One thing that has been extremely effective in fighting the tendency for agents to write complex logic that is prone to
mutation is, of course, mutant testing. Agents are fond of defensive programming techniques in lieu of structural
changes to eliminate classes of bugs. Mutation routinely revealed these areas, and coupled with a draconian 5%
comments-by-total-LOC, it hasn’t been able to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mckayla.blog&#x2F;posts&#x2F;yap.html&quot;&gt;yap&lt;&#x2F;a&gt; its way through. I noticed that
comments were often used to mark ‘traps’ which were actually just bad design in disguise. At one point the agent
complained about having to remove one of &lt;em&gt;seven&lt;&#x2F;em&gt; separate trap comments on a function.&lt;&#x2F;p&gt;
&lt;p&gt;The current work is splitting everything out, the architecture is, as mentioned
&lt;a href=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;log&#x2F;uruk-hai&#x2F;26-aug-2026&#x2F;&quot;&gt;previously&lt;&#x2F;a&gt;, a compilation pipeline from intended-action to some bytecode that’ll run on
an interpreter. Worth noting this is 100% rust until you get to the RL stuff later (&lt;code&gt;uruk&lt;&#x2F;code&gt;), which is python. There is,
therefore, a py03 binding to all this. The thing is broadly split into the following crates:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lurtz&lt;&#x2F;code&gt;: A prelude&#x2F;common re-export site.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lurtz-engine&lt;&#x2F;code&gt;: the bytecode interpreter&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lurtz-python&lt;&#x2F;code&gt;: py03 bindings&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lurtz-srd&lt;&#x2F;code&gt;: The core compilers for action -&amp;gt; bytecode; implements the 2014 and 2024 SRDs.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lurtz-$class&lt;&#x2F;code&gt;: Implementation of class-specific, non-SRD features&#x2F;mechanics&#x2F;etc from the PHB.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;lurtz-{equipment,monsters,spells}-{srd,phb}&lt;&#x2F;code&gt;: specific implementation of spells&#x2F;monsters from the srd&#x2F;phb, per crate.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are internal crate dependencies (&lt;code&gt;lurtz-$class&lt;&#x2F;code&gt; will probably depend on &lt;code&gt;lurtz-spells-*&lt;&#x2F;code&gt; when it enumerates a
spell list for a given class), but I suspect most of those crates to be pretty small. The pattern will extend to cover
splatbooks&#x2F;UA&#x2F;homebrew stuff as needed.&lt;&#x2F;p&gt;
&lt;p&gt;Once I’ve got the split done, I need to start working out how to do some more end-to-end validations. Once tricky thing
here is that I am doing largely a opaque validation here. I need to craft some scenarios that will guarantee various
mechanics get exercised and then validate they’re done correctly. I trust the Cukes because I wrote them, but they
aren’t the obvious “Here is a battle that exercises all the SRD mechanics and ensures they are properly tracked in at
least this instance.” In aggregate these cukes are useful because they ensure the agent stays trying to build the system
I want instead of whatever it invents (and it &lt;em&gt;really&lt;&#x2F;em&gt; likes to invent stuff), but I don’t think it properly validates
the engine.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, I have a different idea. I know some basic facts about D&amp;amp;D. Given a party of a particular composisition and
size, presented with an enemy encounter that relies heavily on a particular underlying feature to provide combat
synergy, absent the correct implementation of the feature the battle will statistically go one way or another. Consider
a party of 3 level 1 fighters, and an encounter with 10 zombies. If the Zombies lack a proper implementation of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.dndbeyond.com&#x2F;monsters&#x2F;17077-zombie&quot;&gt;Undead
Fortitude&lt;&#x2F;a&gt;, then this is roughly equivalent to a &lt;em&gt;nerfed&lt;&#x2F;em&gt; encounter
with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aidedd.org&#x2F;dnd&#x2F;monstres.php?vo=wild-dog&quot;&gt;Wild Dogs&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not limited to ‘real’ monsters, though, I can instead create arbitrary fixture monsters that have a very narrow set
of features that I can incrementally add and remove. In the same way we expect a test to fail under mutation, we should
expect to see the average winrate of some standard party rise or fall under the presence of a new feature added or
removed. My plan is to use exactly this – track objective statistics, like round length, damage done&#x2F;recieved&#x2F;healed,
resource spend, etc. For some features we should see a dramatic change (Undead Fortitude is quite good), but an extreme
change (compared to the change created by other mechanics) indicates an area that needs further review.&lt;&#x2F;p&gt;
&lt;p&gt;The nice thing about this is it’s pretty straightforward to automate. I just need to run a sampling of tests for…
every configuration of party, at every level, against every enemy encounter.&lt;&#x2F;p&gt;
&lt;p&gt;Obviously that’s a little over the top to simply brute force, but I already want to do essentially this anyway for the
big arena training&#x2F;Elo measurement idea; this is just an alternative probe that can help validate the engine is
implemented correctly. Approaching the validation statistically also means that I can generalize a hand validation of
some subset of runs (i.e., I review the produced log and validate it went the way the SRD&#x2F;PHB expects), and then
generalize to all the others from those validated runs.&lt;&#x2F;p&gt;
&lt;p&gt;I have to be careful of &lt;em&gt;interaction&lt;&#x2F;em&gt; corner cases, but my hope is those are relatively few and ideally relatively
well-known already.&lt;&#x2F;p&gt;
&lt;p&gt;Essentially the idea is “Identify some pier points, build the validation on them by statistical self-comparison.”&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Sorry for two different stat sources there, I’m just a DM, a simple innocent DM. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-AUG-2026</title>
        <published>2026-08-26T00:00:00+00:00</published>
        <updated>2026-08-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/uruk-hai/26-aug-2026/"/>
        <id>https://disturbed-circles.com/log/uruk-hai/26-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/uruk-hai/26-aug-2026/">&lt;h1 id=&quot;26-aug-2026&quot;&gt;26-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;0940&quot;&gt;0940&lt;&#x2F;h2&gt;
&lt;p&gt;I’m taking some vacation before &lt;em&gt;Mayhem&lt;&#x2F;em&gt; heads off to kindergarten. This morning is orientation and she is nervous and
excited and off to orientation this morning so I had some time to do some review of &lt;code&gt;lurtz&lt;&#x2F;code&gt;, and something cool
happened.&lt;&#x2F;p&gt;
&lt;p&gt;The design of &lt;code&gt;lurtz&lt;&#x2F;code&gt; has always been a little haphazard owing to the vibe-y nature of it, I knew that going in. I also
knew that it was likely I would step over the SRD&#x2F;PHB line as I am sure Claude is trained – like all the perpetrators
of the grandest larceny in the history of theft – on all the PHB stuff, and it was going to leak in. My understanding
of the SRD and OGL and all that is this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Build whatever you like, these things govern what you &lt;em&gt;distribute&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Distributing stuff based on the SRD content is fine.&lt;&#x2F;li&gt;
&lt;li&gt;If you distribute PHB content, or any other content from WOTC, the full force of the legal department of Hasbro will
set ruin upon thee and thy house for ten generations.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I do not want to piss off Hasbro, but I am sure &lt;code&gt;lurtz&lt;&#x2F;code&gt; has like, PHB and some Arcana and such.&lt;&#x2F;p&gt;
&lt;p&gt;Now, this may seem like a problem if you want to build a D&amp;amp;D engine to manage balance for &lt;em&gt;all&lt;&#x2F;em&gt; of D&amp;amp;D. I agree it is a
constraint, but &lt;code&gt;lurtz&lt;&#x2F;code&gt; can be clever, and part of why I vibecoded it was to sort out how best to design around this.&lt;&#x2F;p&gt;
&lt;p&gt;I knew I wanted a bytecode machine, I wasn’t sure why. I try not to make design decisions like that without having a
reason more than, “Because they’re cool.” When I first started learning Rust, I tried the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Aneurysm9&#x2F;vm_challenge&quot;&gt;synacor&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; challenge, which required building a weird little bytecode
machine among some other fun puzzles I won’t spoil. I’ve really liked these little guys since taking a low-level systems
course in college based on some weird little 16b ISA that had a little simulator and stuff, it was pretty rad. I liked
the architecture enough I started building &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jfredett&#x2F;hazel&quot;&gt;hazel&lt;&#x2F;a&gt; along those lines, before getting
distracted by other shinies and landing here.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I knew I wanted to take that approach, but that didn’t really satisfy me for a reason, I decided eventually
though that a good enough reason was to see how the tokenmachine managed with the architecture.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, fine, I guess. Not great, not terrible. It took a lot of nudging to push it towards that model, and it took a
lot more to keep it there and get it not to re-invent every single wheel. Normally I think these systems have good
API-sense, but in reality what they have is &lt;em&gt;majority&lt;&#x2F;em&gt; API sense. That is, whatever the greatest common subset of APIs
people use, that is what it will inevitably lean to use; and since the APIs themselves are probably part of it’s
training set, there is a &lt;em&gt;huge&lt;&#x2F;em&gt; sample of DIY in there. Since the sorts of libraries for this less common architecture
aren’t as readily available or used as libraries for a more ‘ad hoc&#x2F;amorphous’ architecture&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, it is more likely to
grab a generic, frequently used library for which it has lots of examples, or just DIY everything. I had to point it to
&lt;code&gt;bitmask&lt;&#x2F;code&gt; a bunch of times.&lt;&#x2F;p&gt;
&lt;p&gt;As I was starting to dig through some of the generated code, I started seeing it – &lt;em&gt;PHB-sign.&lt;&#x2F;em&gt; A little scattering of
Battle Master rules has snuck it’s way into the API. I need this code, it’s not going anywhere, by #1 above I can keep
it I just can’t give it away, so the obvious solution is to stick it in a crate. In a &lt;code&gt;lurtz-fighter&lt;&#x2F;code&gt; crate it is safely
tucked away where I can avoid publishing it, but how can I keep it’s PHB-ness off the core engine?&lt;&#x2F;p&gt;
&lt;p&gt;When you design an ISA, you don’t take responsibility for every program written in that ISA, you just design the ISA.
When Intel had its FDIV bug, it was responsible because the ISA was broken. When your software crashes because someone
divided by zero, the author of the software is at fault, not Intel.&lt;&#x2F;p&gt;
&lt;p&gt;In the same way, &lt;code&gt;lurtz&lt;&#x2F;code&gt; doesn’t need to provide direct APIs for any of the mechanics – in any system –
&lt;code&gt;lurtz&lt;&#x2F;code&gt;-as-a-VM should be agnostic to the game system entirely. We need that for 2014&#x2F;2024 support anyway. In a way, you
can think of a battle as an incremental compilation problem. We have a battle-log, I need to turn that sequence of
actions into a sequence of opcodes on a VM such that the state of the VM after executing those codes contains sufficient
information to reconstruct the battle at that state.&lt;&#x2F;p&gt;
&lt;p&gt;That is to say, I can manage some auxillary structure to manage all the things a Battle-Master class would need without
actually implementing the class directly in &lt;code&gt;lurtz&lt;&#x2F;code&gt;. This is a much better reason and I retroactively use &lt;em&gt;this&lt;&#x2F;em&gt; one as
justification for this model. It has some nice knock-on effects too.&lt;&#x2F;p&gt;
&lt;p&gt;Right now &lt;code&gt;lurtz&lt;&#x2F;code&gt; is one big crate with everything piled in. It has an action API for all the things you can do in D&amp;amp;D,
it has the engine itself, all the opcode stuff, everything, one big pile. Obviously I can split out &lt;code&gt;lurtz-$class&lt;&#x2F;code&gt; like
mentioned, but also &lt;code&gt;lurtz-monsters&lt;&#x2F;code&gt; and &lt;code&gt;lurtz-players&lt;&#x2F;code&gt; can be split out. Players and Monster statblocks both translate
to ‘intialization’ opcodes that start a battle log and configure the environment. These translate into datastructures
inside the VM as well. I can then further split out &lt;code&gt;lurtz-srd&lt;&#x2F;code&gt;, which contains the core SRD actions, upon which all
these other crates depend, now &lt;code&gt;lurtz&lt;&#x2F;code&gt; is the &lt;em&gt;core&lt;&#x2F;em&gt; crate with &lt;em&gt;only&lt;&#x2F;em&gt; the engine in it. Each crate can have it’s own
validation set, which we compile and assert on the engine state. These now track the implementations much more tightly,
which will greatly improve my ever growing mutant problem.&lt;&#x2F;p&gt;
&lt;p&gt;It has a natural extension pattern as well, new UA or splatbooks can be included as another crate, independently tested.
It means that &lt;code&gt;lurtz&lt;&#x2F;code&gt; can be optimized aggressively for the GPU and the ‘compiler’ crates can expect to run more or less
uninterrupted on the CPU. I suppose in the final tally the training process probably looks like some number of agents
playing as many games as they can on the GPU; they make a big pile of next move decisions while the CPU grabs those
moves, compiles them, and sends them back to the engine to update in parallel. I’m not sure if I could get 100% of that
loop on the GPU but it doesn’t seem &lt;em&gt;impossible&lt;&#x2F;em&gt;. That’s either inexperience or very clever, I’m not sure which.&lt;&#x2F;p&gt;
&lt;p&gt;It also leaves open a door to test other combat systems. Pathfinder is an obvious target, but there are lots of systems
that look like D20-style combat.&lt;&#x2F;p&gt;
&lt;p&gt;All this would’ve probably been findable with a whole bunch of anxious thought about how things might work. By the time
I got there I’d’ve been so worried about implementing it wrong I’d’ve given up. I’ve put about two proper weeks of
thought into &lt;code&gt;lurtz&lt;&#x2F;code&gt; at this point and have a working program. It’s not good, it’s not super well factored (yet), but
it’s reasonably functional and it’s easy enough to change. Because I had a working program, I was able to &lt;em&gt;see&lt;&#x2F;em&gt; this
refactor, instead of having to &lt;em&gt;imagine&lt;&#x2F;em&gt; it ahead of time. I can look at this code and this structure falls out.&lt;&#x2F;p&gt;
&lt;p&gt;I will &lt;em&gt;definitely&lt;&#x2F;em&gt; need to rewrite every one of these crates at some point&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but having them to hand when finding
the architecture makes code feel &lt;em&gt;much&lt;&#x2F;em&gt; more play-doh than it used to.&lt;&#x2F;p&gt;
&lt;p&gt;I quit working on &lt;code&gt;hazel&lt;&#x2F;code&gt; partially because I was getting lost down a rabbit hole of screwing with the trait system to
do some weird message passing stuff. I also quit on it because I kept running into problems that needed a big fat
refactor that would take days of churning over error messages and making tiny adjustments. If it weren’t for the fact
that I &lt;em&gt;do&lt;&#x2F;em&gt; want to keep one project as agent-free as I can, I’d be using an LLM for those changes today and probably
still be working on it. That hypothesis is supported by this result with lurtz. My favorite part of coding is
refactoring, because it is really difficult to hold both the observed and the desired in your head at the same time;
much less to plot a course from one to the other. My strategy has been to rely on good observation skills and git to
slowly move from one to another. LLMs offer a new option here. &lt;code&gt;lurtz&lt;&#x2F;code&gt; has been sort of ‘3d printed’ into place. It’s
cheap plastic, it’s all one mold instead of several moving parts, but it gives me an object I can hold in my hands.&lt;&#x2F;p&gt;
&lt;p&gt;I occasionally turn wood; mostly to make handles for stuff. One of the things about turning handles is that – while you
need a template to get a repeatable result, no two handles are ever finished exactly alike. You always use the same
process, or at least I do:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Turn stock to the template dimensions&lt;&#x2F;li&gt;
&lt;li&gt;Cleaning pass with a skew&lt;&#x2F;li&gt;
&lt;li&gt;Rough pass with 60 grit&lt;&#x2F;li&gt;
&lt;li&gt;Stop lathe, feel the handle.&lt;&#x2F;li&gt;
&lt;li&gt;Start lath, skew or sand.&lt;&#x2F;li&gt;
&lt;li&gt;Repeat 4 and 5 until it’s right, adjust grit as necessary.&lt;&#x2F;li&gt;
&lt;li&gt;Friction polish with BLO, Wax on the Lathe, Buff.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;You can’t make a handle for something without trying to use it first, there is no substitute for holding it in your
hand. Trying to divine this architecture for &lt;code&gt;lurtz&lt;&#x2F;code&gt; ahead of time, especially given my vanishingly close to zero prior
experience in game making, would’ve been like trying to make a perfect handle template – not possible.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, this was a very nice validation of what I hoped would happen when I started this, I had hoped that LLMs
would work nicely this way and it has. I have a natural skeleton to build the next version of this against, and all it
took was two weeks of prompting, not exclusively on this but majority on this, most of which were status report requests
&#x2F; disambiguating parts of the plan. I’ll talk about how I set up this project another time. I kept all the conversations
archived so I should be able to do some forensics on it.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;The original challenge page is down, this is a mirror I found
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;adventofcode&#x2F;comments&#x2F;11pjsxk&#x2F;synacor_challenge_unable_to_load_domain_is_it&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;. I hope it
comes back at some point, but maybe someone oughta just build a new one. :) &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;I couldn’t find a way to make that not sound perjorative. I don’t mean it that way. Ad hoc architecture is not a
crime, it’s a choice with trade-offs. &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;I wrote that and immediately went to hedge – maybe this is true, but I could see a world where I rewrite &lt;em&gt;some&lt;&#x2F;em&gt;
of the crates, then make the machine &lt;em&gt;copy&lt;&#x2F;em&gt; that style to the others. Still a rewrite, but by what fraction? &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>25-AUG-2026</title>
        <published>2026-08-25T00:00:00+00:00</published>
        <updated>2026-08-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/disturbed-circles/25-aug-2026/"/>
        <id>https://disturbed-circles.com/log/disturbed-circles/25-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/disturbed-circles/25-aug-2026/">&lt;h1 id=&quot;25-aug-2026&quot;&gt;25-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1352&quot;&gt;1352&lt;&#x2F;h2&gt;
&lt;p&gt;Added some quotes to the rotation, I don’t love how I have it set up right now, probably will move to a single
structured file that compiles to the multiple files at build time or something, good enough for now though.&lt;&#x2F;p&gt;
&lt;p&gt;Work on stuff here has slowed as I’ve been working much more on getting the kiddo ready for kindergarten, and planning
an &lt;a href=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;log&#x2F;office&#x2F;14-aug-2026&#x2F;&quot;&gt;office move&lt;&#x2F;a&gt; to a much larger space. I’ve started thinking again about a whole-lab
&lt;em&gt;sound&lt;&#x2F;em&gt; setup as well. It’s been on my punchlist for several years now to build some sort of network-attached-sound
system. I have a number of SFFs and RPi’s that connect to most of the noisemaking things in my house and a many-to-many
mapping system would be a very nice thing.&lt;&#x2F;p&gt;
&lt;p&gt;It coincides with me wanting to push my current daily driver machine, a M2 Studio named &lt;code&gt;Hedges&lt;&#x2F;code&gt;, to be more of a
dedicated music&#x2F;recording machine and less of a ‘do everything’ machine. When I initially concieved of it, I had planned
an analog approach of just sending everything’s sound to a central mixing console, and then having the channels AUX into
&lt;code&gt;Hedges&lt;&#x2F;code&gt; UMC1820, but this would only ever really be useful in relatively small area, as I don’t want to try to run the
50m of speakerwire through walls, especially given it’d need to be shielded. I looked into using
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jackaudio.org&#x2F;&quot;&gt;JACK&lt;&#x2F;a&gt; at the time and plan to look again, but I planned all of this in the days where wiring up
JACK required what felt like a PhD in audio engineering, I’m hoping LLMs can take some sting out of it for me. I’m not
looking to be a pro audio routing engineer here, just get my noises all filed into one box where I can mangle them and
spit them out into my ears.&lt;&#x2F;p&gt;
&lt;p&gt;Much of that work may be hidden as I haven’t sorted out a way to expose my monorepo that doesn’t also expose the
absolute &lt;em&gt;mess&lt;&#x2F;em&gt; that is my monorepo. Most of my projects start out as subprojects of &lt;code&gt;angband&lt;&#x2F;code&gt;. &lt;code&gt;angband&lt;&#x2F;code&gt; currently
contains the live version of &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt;, the homelab infrastructure from metal -&amp;gt; k8s running services; &lt;code&gt;truncheon&lt;&#x2F;code&gt;
and all it’s constituent parts (including &lt;a href=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;log&#x2F;uruk-hai&#x2F;whom-do-you-serve&#x2F;&quot;&gt;an army &lt;em&gt;worthy&lt;&#x2F;em&gt; of Mordor&lt;&#x2F;a&gt;); and a
bunch of other stuff that’s worth talking about, but not necessarily sharing code for (yet). I set up
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;josh-project&#x2F;josh&quot;&gt;josh&lt;&#x2F;a&gt; a while ago and have half an idea about using it to extract some of the
code to mirror repos. The main issue is most of the monorepo is unsharable because I don’t build those projects with the
intent of public use, so I’m quite happy to hardcode all sorts of stuff about my system and network. For instance, I
have in that repo a tool called &lt;code&gt;thrak&lt;&#x2F;code&gt;. &lt;code&gt;thrak&lt;&#x2F;code&gt; is a CLI for the monorepo itself, it is not a very well made CLI, but
more because it has no specific remit other than, “I need a place for this specific tool to live that I can use from my
laptop when I’m in this repo.” Some people use &lt;code&gt;just&lt;&#x2F;code&gt; or &lt;code&gt;make&lt;&#x2F;code&gt; or &lt;code&gt;rake&lt;&#x2F;code&gt; or whatever, I’ve been all those people, but
at some point I always end up thinking, “If only I’d just written a damn CLI, I wouldn’t be wondering about the call
order or having to write so much friggin’ shell.”&lt;&#x2F;p&gt;
&lt;p&gt;I suppose probably the better thing to do is a careful migration where the tool is built first and projects imported,
but that is a lot of work for a tool that has a constituency of one.&lt;&#x2F;p&gt;
&lt;p&gt;Since ‘constituency of one’ describes most of those projects, most of those projects are not really the sort of thing
I’d feel great putting out into the world, and so much remains hidden.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t have a solution I just felt like writing a bit today and this is what came out.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Whom do you serve?</title>
        <published>2026-08-25T00:00:00+00:00</published>
        <updated>2026-08-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/uruk-hai/whom-do-you-serve/"/>
        <id>https://disturbed-circles.com/log/uruk-hai/whom-do-you-serve/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/uruk-hai/whom-do-you-serve/">
&lt;div class=&quot;video&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;shz8OzPmHfw&quot;
    title=&quot;YouTube video&quot;
    loading=&quot;lazy&quot;
    referrerpolicy=&quot;strict-origin-when-cross-origin&quot;
    allow=&quot;accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot;
    allowfullscreen
  &gt;&lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;h1 id=&quot;dungeon-mastery&quot;&gt;Dungeon Mastery&lt;&#x2F;h1&gt;
&lt;p&gt;Hi, I’m Joe, and I’m a forever-DM.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chorus: “Hi, Joe.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I’ve been forever-DMing since around 2015, I played a bit in college before that and ran a one-shot or several, but it
wasn’t until then that I’d tried to run anything homebrew. Up until then I’d played canned encounters that had been
extensively playtested, I’m sure, by folks who were quite good at the game and who made sure that the encounters would
be balanced nicely.&lt;&#x2F;p&gt;
&lt;p&gt;It’s not, therefore, my or my player’s fault when I would routinely trounce them. I had all the advantages. I knew their
characters, I knew the monsters; it simply wasn’t my fault that playing the game &lt;em&gt;well&lt;&#x2F;em&gt; meant also not playing for very
&lt;em&gt;long&lt;&#x2F;em&gt; because it turns out ‘being everything else’ means you get to create pretty favorable conditions. I did what all
DMs do, then, I started to pull punches.&lt;&#x2F;p&gt;
&lt;p&gt;It wasn’t hard to justify, but it wasn’t fun for me anymore. I instead focused on big narratives that were occasionally
peppered with quite combat. This led to burnout as I’d plan for one set of things and have to replan when the players
went right instead of left. Then I thought, “I’ll go back to modules; better balance there.” Except I don’t &lt;em&gt;like&lt;&#x2F;em&gt;
modules, because it turns out what had been balancing them for me wasn’t the design, but rather my own inability with
the game. I practiced, practice perfects, and so suddenly because I was playing, essentially, 5x the D&amp;amp;D as anyone else;
managing dozens of characters and learning statblocks and rules deeply and confidently, I was simply &lt;em&gt;better&lt;&#x2F;em&gt; at the
game than my players. It became a problem to the point of needing to nerf fights preemptively, make a lot of “well this
monster &lt;em&gt;does&lt;&#x2F;em&gt; have a -1 int modifier so maybe they’re just stupid and die.”&lt;&#x2F;p&gt;
&lt;p&gt;It sucks. There has to be a better way.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;go&quot;&gt;Go&lt;&#x2F;h1&gt;
&lt;p&gt;In 2013, a company in London published some work about the use of reinforcement learning to play some simple (in terms
of size-of-inputspace games) like &lt;em&gt;Breakout&lt;&#x2F;em&gt;, &lt;em&gt;Pong&lt;&#x2F;em&gt;, and others (which were nonetheless complex in their
&lt;em&gt;outputspace&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;). This technique led to extremely good play, and moreover, it generalized to other games like &lt;em&gt;Space
Invaders&lt;&#x2F;em&gt;, &lt;em&gt;Beamrider&lt;&#x2F;em&gt;, and &lt;em&gt;Q*bert&lt;&#x2F;em&gt;. In 2015, this same company decided to take on a real giant, &lt;em&gt;Go&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Go is a two-player abstract game about placing stones in a grid. The rules are simple and I do not know them. I am sure
Go is a lovely game to play, I don’t particularly care for it. I have trouble reading a go board, worse than a chess
board (and I’m bad at reading those too). I don’t know if it’s the dyslexia or if I’m just the wrong kind of nerd for
it, but Go has always bounced off my brain.&lt;&#x2F;p&gt;
&lt;p&gt;What hasn’t bounced off, though, is the fact that Go is a very &lt;em&gt;deep&lt;&#x2F;em&gt; game. For some perspective, we can think about it
in the context of Chess. Chess, ultimately has only 32 pieces, with limited movesets, on a 64 square board. Number of
possible games of chess is astronomical, and the most powerful engines, playing in real time, might search 30 plies
(about 15 full moves) ahead. That search might take a few seconds on a modern computer.&lt;&#x2F;p&gt;
&lt;p&gt;Comparatively, Go is much simpler, there are only two kinds of pieces, but the board is &lt;em&gt;much&lt;&#x2F;em&gt; bigger at 19x19, and the
number of possible moves is essentially &lt;code&gt;19*19 - number-of-occupied-squares&lt;&#x2F;code&gt;, which is &lt;em&gt;extremely&lt;&#x2F;em&gt; large after even a
few ply. The technical term here is that Go has a high ‘branching factor’, and there are many more moves to be made. As
a result, good play still needs to look very far ahead, and looking far ahead is much harder, and in fact since the
&lt;em&gt;pieces&lt;&#x2F;em&gt; do less, looking &lt;em&gt;even&lt;&#x2F;em&gt; further is more necessary to determine good play. For many years, Go was unassailable
by computer; even the best programs only achieving slightly-better-than-amateur level play.&lt;&#x2F;p&gt;
&lt;p&gt;We’re talking Stockfish Level 3 on lichess kind of play. I remember trying to learn go and being able to occasionally
beat the best engine on it’s hardest setting in 2012, so the gap was wide.&lt;&#x2F;p&gt;
&lt;p&gt;In 2015 though, DeepMind released AlphaGo, which combined statistical analysis and RL techniques to play Go
significantly better than humans, famously beating very strong Go players like Lee Sedol and Ke Jie.&lt;&#x2F;p&gt;
&lt;p&gt;Why am I telling you about AlphaGo?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;complexity-requires-learning&quot;&gt;Complexity requires Learning&lt;&#x2F;h1&gt;
&lt;p&gt;D&amp;amp;D is a complex game. There are a dozen classes, each of which has unique mechanics, spells, abilities, and
customizations. There are hundreds of monsters with their own abilities and mechanics. There is an entire environment to
interact with, move through, and exploit. The combat system itself introduces effects, optional moves, resources to
manage, and many more besides.&lt;&#x2F;p&gt;
&lt;p&gt;D&amp;amp;D is also a simple game. Almost everything comes down to a few multiple choice questions. “I have some resources, I want to
accomplish Y goals, I can choose to spend resources on abilities to alter the state of the game.” Every action is built
out of the same parts. Checks and Saves measure a roll against a threshold; Contested Checks roll against a dynamic
threshold; Value rolls tell you how much of something happens. There are no other real roll types in D&amp;amp;D, and almost
every action is some cipher of “Roll some combination of Check or Saves, Contested Check, or Value rolls and make a
state update based on the result.”&lt;&#x2F;p&gt;
&lt;p&gt;It’s not hard to play D&amp;amp;D because the mechanics are easy. It’s &lt;em&gt;very&lt;&#x2F;em&gt; hard to be good at D&amp;amp;D because there are so many
variants of the mechanics and so many variables to consider in how the results of your actions might interact with the
world.&lt;&#x2F;p&gt;
&lt;p&gt;That is to say, D&amp;amp;D has pretty &lt;em&gt;limited&lt;&#x2F;em&gt; input space, but a &lt;em&gt;wide&lt;&#x2F;em&gt; output space. Sound familiar?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;alphadm-uruk-hai&quot;&gt;&lt;del&gt;AlphaDM&lt;&#x2F;del&gt; Uruk-hai&lt;&#x2F;h1&gt;
&lt;p&gt;I actually don’t want to replace myself entirely, I’m reminded of a Brennan Lee Mulligan conversation where he lays out
the primary reason he uses D&amp;amp;D as opposed to some other ruleset is precisely because D&amp;amp;D combat is deep and rich, and
it’s an area where he doesn’t have a lot of experience. His battle scenes are relatively few in number, they’re
generally set pieces, and I am positive he has access to &lt;em&gt;actual&lt;&#x2F;em&gt; playtesting, which makes this make lots of sense. If
you’re trying to do all that on your own though, it’s quite difficult.&lt;&#x2F;p&gt;
&lt;p&gt;I also want a combat system I don’t have to think about. To be honest, there are times where it’d be nice to say,
“Alright combat is happening I need to jump in for the occasional bit of narration but otherwise it runs itself.”&lt;&#x2F;p&gt;
&lt;p&gt;To that end, I started on &lt;code&gt;uruk-hai&lt;&#x2F;code&gt;. This is a collection of projects, with the goal, ultimately, it so ‘solve’ balance
by experimentation. &lt;code&gt;lurtz&lt;&#x2F;code&gt; is a D&amp;amp;D combat engine, supporting both the 2024 and 2014 editions of the 5e ruleset.
Eventually I’d like to try to include other combat systems (you’ll understand how and why in a moment). &lt;code&gt;uruk&lt;&#x2F;code&gt; learns to
play optimal D&amp;amp;D by self-training via &lt;code&gt;lurtz&lt;&#x2F;code&gt;, &lt;code&gt;orthanc&lt;&#x2F;code&gt; records an analog of “Elo” score based on an open arena model.
You create an encounter and let it fight hundreds or thousands of times against ‘perfect’ players, and determine how it
fairs against different party and power compositions.&lt;&#x2F;p&gt;
&lt;p&gt;I intend to integrate this with FoundryVTT at some point and allow it to manage combat to some extent directly; the GM
sets an encounter, simulate it against their player’s party composition, and then adjust the agent to modify difficulty
on the fly.&lt;&#x2F;p&gt;
&lt;p&gt;It’s also just a pretty fun data problem, the design of &lt;code&gt;lurtz&lt;&#x2F;code&gt; is cool as it is intended to be runnable on the GPU
directly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;lurtz&lt;&#x2F;code&gt; is &lt;em&gt;also&lt;&#x2F;em&gt; a fully autonomous project. I wrote precisely none of it’s code (and it definitely &lt;em&gt;looks&lt;&#x2F;em&gt; like
agent-written code), but instead spent quite a long time building a suite of validation tests without ever having
written any actual code. Instead, each action is &lt;em&gt;compiled&lt;&#x2F;em&gt; to an abstract machine that Lurtz can run. An action like
“Cast Firebolt at $Monster” gets turned into a sequence of Opcodes like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    set_caster $Current&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    set_target $Monster&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    spend_action $Current&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if attack hits $monster:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        set_damage_type(Fire)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        do_damage(1d10)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I built these in tandem with the machine, I’d write a narrative, walk through what the engine should do, and then write
some opcodes. The machine kept track of which opcodes we added, we’d iterate a bit to ensure some minimal set, and
design Cucumber scenarios to capture that the engine produced the expected output sequence. Once I was sure these
validation tests were roughly correct, I set the machine off to implement the underlying spec.&lt;&#x2F;p&gt;
&lt;p&gt;This underlying VM is generic across editions and aims to be system agnostic more generally. Since each action is
essentially an instantiation of some underlying template, this allows us to minimize the actual number of needed
opcodes to go from “I cast Firebolt at Monster” to an actual implementation. It also let’s us be extensible since
future mechanics just need to provide a compilation path.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;em&gt;other&lt;&#x2F;em&gt; upside of this is the “VM” here can be made quite lean; and since we already depend on a seeded RNG, we can
potentially run many of these on a single GPU along with the RL agents being trained on it. By locating many of these on
a GPU, we can have a single RL process playing many games simultaneously without ever leaving the GPU; which I hope will
improve training speed.&lt;&#x2F;p&gt;
&lt;p&gt;My plan is to use an open-arena approach to training; early experiments show this is a quite servicable way of running
training that gives good convergence rate while allowing for some other training benefits; in particular
drop-in&#x2F;drop-out compositions. This model allows for some very convenient experiments:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Given a fixed party of PCs, assuming they play optimally, what encounters exist that are within a few hundred Elo of
the party?&lt;&#x2F;li&gt;
&lt;li&gt;Given a fixed party of PCs, what is the effect on the party’s Elo of giving one specific PC an item with a unique
combat ability?&lt;&#x2F;li&gt;
&lt;li&gt;What is an optimal composition of PCs given a fixed XP budget to spend?&lt;&#x2F;li&gt;
&lt;li&gt;Given an enemy encounter, what is the incremental effect of swapping one monster for another of equivalent CR?&lt;&#x2F;li&gt;
&lt;li&gt;How closely does CR map to the statistical reality of the monster it describes? That is, across some large number of
compositions, what is the net effect of adding&#x2F;removing the monster on any such encounter, and how closely does that
effect match other monsters of that CR?&lt;&#x2F;li&gt;
&lt;li&gt;Given two encounters of equivalent CR, how closely do they perform against a wide variety of party compositions of
appropriate level?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I dislike CR because it is a one-dimensional description of a very high dimensional problem, and in many ways &lt;code&gt;uruk-hai&lt;&#x2F;code&gt;
is way to try to understand exactly what CR measures and how well it actually does it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;lurtz&lt;&#x2F;code&gt; being fully-autonomous&#x2F;‘vibed’ also serves another purpose. I suspect that this class of code will shortly be
the majority of code. Agents can easily produce far more LOC than any human, even the most hyperlexic among us, and
because it works even a little, it will almost certainly dominate every codebase. The question is not ‘if’, but ‘when’,
and ‘how do we deal with it.’&lt;&#x2F;p&gt;
&lt;p&gt;Practice perfects, and one cannot practice without examples. I hate toy examples, and &lt;code&gt;lurtz&lt;&#x2F;code&gt; is not a toy example. It
currently is running around 100KLOC, I suspect if I were working from scratch and doing it by hand I’d be in the 50KLOC
region. Many of those lines are Claudes &lt;em&gt;insufferable&lt;&#x2F;em&gt; commenting habit, but I would guess there is around 80-90KLOC of
actual code there, and much of it is quite bad. My goal was not to produce good code here, just working code. The spec
took about two weeks of conscious effort and back and forth iteration with the machine, but the engine has been getting
churned on for about 2-3 solid weeks of a majority of my token budget from a 20x Max plan of Claude.&lt;&#x2F;p&gt;
&lt;p&gt;Part of the relative slowness in development (and incidentally while this doesn’t feel particularly ‘vibecoded’ to me,
despite me having written no code and read fairly little of it) is how I’ve approach coding standards, but part of it I
think is intrinsic to the way LLMs work with codebases. Right now the standard is “0 failing tests, &amp;gt;99% line and branch
coverage, 0 warnings, 0 lints, ~0 mutant survivors.” These are much higher standards than I set for myself (I am
personally quite pleased with ~80-90% coverage and ‘relatively few’ mutant survivors), but in this context they have
managed to keep the output results reasonably sane despite being fully hands off. This led to a whole sidequest of
getting mutant runs sharded across my R730s and other equipment so I could shrink the runtime from 4d -&amp;gt; 4h&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My plan now is to finish the remaining items on &lt;code&gt;lurtz&lt;&#x2F;code&gt;’s implementation; and get my ~400 scenario suite passing. Then
I’m going to take some stock before letting the machine refactor the heck out of it, and trying to find any corners I
can to flesh out the suite. Once that’s done, I plan to write a &lt;em&gt;second&lt;&#x2F;em&gt; implementation using my preferred LLM-involved
workflow, which is “I implement some stuff, then when it’s tedious refactor time, the machine takes over.” I’ll probably
do this while getting the RL side (&lt;code&gt;uruk&lt;&#x2F;code&gt;) hooked back up (early iterations of &lt;code&gt;lurtz&lt;&#x2F;code&gt; implemented a simple version with
only melee combat and did the full training flow with open arena&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Once I can reproduce a similar result with the current engine, and I’m confident it’s actually compliant and mostly
bug-free, I’ll be able to start doing some of those big training items and probably porting to GPU as I mentioned.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;By this I mean; there are many simple actions that can be taken, the immediate effects of which are easy to
predict, but the distant effects of which are much harder to predict. In &lt;em&gt;Breakout&lt;&#x2F;em&gt;, this is the number of bricks
and the exact pattern you have made allowing for different, more efficient strategies in quickly clearing bricks. In
&lt;em&gt;Pong&lt;&#x2F;em&gt;, it’s the fact that while returning the ball is easy, knowing how your opponent might return it is not. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;Along the way I accidentally reinvented the concept used by the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llogiq&#x2F;mutagen&quot;&gt;mutagen&lt;&#x2F;a&gt;
project, which seems to be pretty dead (and also tied to a proc-macro which makes it hard to maintain, I imagine).
I have some hazy thoughts about trying something similar but re-using the mutator code in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mutants.rs&#x2F;&quot;&gt;cargo-mutants&lt;&#x2F;a&gt;
to tag the IR in the right spots and hopefully avoid the need for a proc-macro&#x2F;syntax hacking by directly modifying
the IR. The majority of time spent mutation-testing is compilation, so even avoiding a few such recompilations
could save many minutes in the long run. Even doing this &lt;em&gt;solely&lt;&#x2F;em&gt; for the binops would probably be enough to take
my current 4h sharded run to like, an hour. &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;This is the only image I have from those runs. You can see it correctly sorts, though there are some monsters ‘out
of place’ with respect to their CRs. For the most part I think this is unimplemented mechanics for those monsters,
and the fact that this is all monsters-fighting-monsters, which is it’s own area of research.&lt;&#x2F;p&gt;


&lt;a class=&quot;figure&quot; href=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;images&#x2F;elo-lurtz-uruk.png&quot;&gt;
  &lt;img src=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;processed_images&#x2F;elo-lurtz-uruk.1c0c1e8d8ed0c5fd.png&quot;
       width=&quot;1100&quot; height=&quot;551&quot;
       alt=&quot;Grafana dashboard from a training run: an Elo leaderboard, Elo over time fanning out from 1500, Elo by fight number, and panels for rounds per fight and fight duration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
&lt;&#x2F;a&gt;
 &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>17-AUG-2026</title>
        <published>2026-08-17T00:00:00+00:00</published>
        <updated>2026-08-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/disturbed-circles/17-aug-2026/"/>
        <id>https://disturbed-circles.com/log/disturbed-circles/17-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/disturbed-circles/17-aug-2026/">&lt;ul&gt;
&lt;li&gt;[~] other projects in the log section that come from content managed here
&lt;ul&gt;
&lt;li&gt;mostly for projects that don’t really have natural repos of their own.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Project Nobby&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
The Garden&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
The Office&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;[~] Music section?
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Links to playlists&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Guitar inventory&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Work&lt;&#x2F;li&gt;
&lt;li&gt;Might could harvest some stuff from the old site?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Gehenna
&lt;ul&gt;
&lt;li&gt;A place where i drop ideas that I probably will never get to. I have very many of these.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
FTA
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
HTML Gen
&lt;ul&gt;
&lt;li&gt;probably should follow the reorg&#x2F;citation thing. Idea would be to take each env and include citation info
in it directly, then extract to some input format. Later I can add equivalent citation (i.e., where in
Munkres a def appears or something).&lt;&#x2F;li&gt;
&lt;li&gt;not sure if I should keep it as latex as the primary language or extract to a different format&#x2F;convention&lt;&#x2F;li&gt;
&lt;li&gt;aim is Temu nLab, all my notes + cited definitions across my various books. One big map. Queryability would be
nice. Maybe a graphdb – ideally an atlas integration?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;17-aug-2026&quot;&gt;17-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1528&quot;&gt;1528&lt;&#x2F;h2&gt;
&lt;p&gt;Work in the lab on getting my jellyfin container properly pinned to the GPU node in my cluster. I need to think about
GPU sharing at some point (everything just pins down to one of the cards in the fleet, occupying the whole thing).&lt;&#x2F;p&gt;
&lt;p&gt;I’ve got some more subsections set up, and I need to spend some time porting stuff from the old site here, but I’m
pretty happy with how this is working out. Most of the sidebar is just pointing directly at repos and builds dynamically
from the LOG.md there, so I can keep my notes local and still have them centralize here. Much nicer than the obsidian
site I was running for a while.&lt;&#x2F;p&gt;
&lt;p&gt;I am in the final stretch for my topology refresher and then I think I’m going to do the same with Hungerford, I’m
debating if I want to formalize it as I go or not. I really like algebra so it would be cool to formalize it, but I’m
starting to think I’m just procrastinating because I’m not confident the idea I have for GIYF is going to work how I
want. Anxiety is a complicated and frustrating thing.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Music isn&#x27;t the sound that music makes</title>
        <published>2026-08-14T00:00:00+00:00</published>
        <updated>2026-08-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/music/music-isnt-the-sound/"/>
        <id>https://disturbed-circles.com/log/music/music-isnt-the-sound/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/music/music-isnt-the-sound/">&lt;p&gt;When I was first learning guitar, I went through a series of teachers. The first, a young man named Chris, he was in his
20s and wildly unprepared for the degree of weird I was going to bring. I was raised Evangelical&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; So my musical
horizons were limited to ‘approved’ music: hymns, classical music, and ‘CCM’&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. CCM, if you are unfamiliar, is the sort
of sacchyrine, flavorless drivel that takes a bad love song and replaces the object of affection with Jesus. There are certainly some tunes that rise above the tepid dreck, but only few, and never by much.&lt;&#x2F;p&gt;
&lt;p&gt;Chris liked to play Rock and Roll, Chris liked the Blues. Chris was confused when I asked him to teach me an Amy Grant
tune. Eventually Chris gave up. Though he did introduce me to Delta Blues, so six-of-one.&lt;&#x2F;p&gt;
&lt;p&gt;After a brief interregnum, I ended up with my second teacher. Shirley was a very nice lady from Church, she played piano
and guitar, and thought that meant she could teach it. This is not an uncommon mistake people make, teaching is a
different problem than simple knowing. Shirley failed like all the others, I only had lessons with her for a few months.
Chris outlasted her.&lt;&#x2F;p&gt;
&lt;p&gt;Another few months, another teacher from Church, she taught piano to my sister. She lasted two lessons and told me that
it was impossible to play the guitar without a pick. She wasn’t a very good player, either, having only picked up the
instrument a few months prior. Come to think of it I might’ve actually been playing longer than she had when she tried
to teach me.&lt;&#x2F;p&gt;
&lt;p&gt;There was a long gap after that. I first got the guitar around 8 or 9, cheap Samick that probably cost 80$ at the time.
The action was too high, and the intonation was trash. I broke a string, but no one ever explained that that was normal
and you could just change them, so I played with no high E for a year or so. Finally I started taking lessons with Ron
from a music store one town over when I was about thirteen or so.&lt;&#x2F;p&gt;
&lt;p&gt;Ron was, and remains, probably the best teacher I’ve had in any subject in my life. I had great teachers in college, but
Ron was the first teacher to take an honest interest in what I wanted out of guitar.&lt;&#x2F;p&gt;
&lt;p&gt;Our first lesson was pretty funny. I kept my guitar in the cardboard box it came in. No gig bag, certainly no hardcase.
I dragged it up the stairs to the small practice room and pulled it out, ancient strings, one missing.&lt;&#x2F;p&gt;
&lt;p&gt;“Okay, ooh, nice guitar, looks like you broke a string though.”&lt;&#x2F;p&gt;
&lt;p&gt;“Yah, few months ago.”&lt;&#x2F;p&gt;
&lt;p&gt;“You didn’t replace it?”&lt;&#x2F;p&gt;
&lt;p&gt;“You can replace them?”&lt;&#x2F;p&gt;
&lt;p&gt;For the next year or so, Ron taught me how to learn guitar. He didn’t merely teach me how to play, but how to think
about playing. I think of this now whenever I think about teaching anything, the hard part of teaching is not the
content of the subject, but the narrative of the subject. He introduced this concept early with one of my favorite music
exercises.&lt;&#x2F;p&gt;
&lt;p&gt;“Play it wrong.”&lt;&#x2F;p&gt;
&lt;p&gt;“What? What do you mean play it wrong?”&lt;&#x2F;p&gt;
&lt;p&gt;“Take what you’re doing, the notes you’re playing, and screw up. I want you to play it off by fret or three.”&lt;&#x2F;p&gt;
&lt;p&gt;“But it’ll sound terrible.”&lt;&#x2F;p&gt;
&lt;p&gt;“Not in your head, that’s where I want it, don’t worry about the sound you’re making, listen to the music and just do
whatever feels natural. Be okay with it sounding wrong, that’s going to happen a lot.”&lt;&#x2F;p&gt;
&lt;p&gt;“But it sounds bad when I do that.”&lt;&#x2F;p&gt;
&lt;p&gt;“Play it anyway, even if it sounds bad, Music isn’t the sound that music makes, Music is in your mind, you have to
listen for it, chase it, sit in it, let it soak into your brain. Don’t try to force it, just let it move your hands, let
it move you, worry about the mechanics later.”&lt;&#x2F;p&gt;
&lt;p&gt;Ringing in my mind, ever since, has been those words, “Music isn’t the sound that music makes.”&lt;&#x2F;p&gt;
&lt;p&gt;I didn’t understand that lesson till many years later. After a few years of therapy for (what I assumed was) unrelated
Anxiety, I began to notice something happening to my guitar playing.&lt;&#x2F;p&gt;
&lt;p&gt;I sounded good, like really good. I was enjoying what I played more, I was listening to what I played more. I didn’t
feel the same need to control it anymore, to make it perfect, I could just play. As I sat in front of my daughter, I
remember hearing myself play her tune&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and in my mind like a siren, “Music isn’t the sound that music makes.”&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been afraid for a majority of my adult life that if anyone ever heard me play, that the facade would break, and I
would be revealed an imposter. I’ve worried that they would tell me I was awful, and this thing which I love so much
would be ruined by their judgement. I still worry about that, but I’m working on it.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;This is a very deep hole I crawled out of; maybe someday I’ll talk more about how. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;“Christian Contemporary Music” &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;log&#x2F;music&#x2F;music-isnt-the-sound&#x2F;www.youtube.com&#x2F;watch?v=kKm9vgMFn_I&quot;&gt;This&lt;&#x2F;a&gt; is a good enough version as any to share. There is a specific motive I
use a lot, that’s what I mean when I say this. &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>So what sound will I make?</title>
        <published>2026-08-14T00:00:00+00:00</published>
        <updated>2026-08-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/music/so-what-sound-will-i-make/"/>
        <id>https://disturbed-circles.com/log/music/so-what-sound-will-i-make/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/music/so-what-sound-will-i-make/">&lt;p&gt;Well, I’m going to start by posting &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=kKm9vgMFn_I&quot;&gt;this, my youtube channel&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It’s on the frontpage, obviously, but worth posting the direct link.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;disturbed-circles.com&#x2F;log&#x2F;office&#x2F;14-aug-2026&#x2F;&quot;&gt;Right now I’m prepping to move my office where I currently record.&lt;&#x2F;a&gt;, so I probably won’t
have much in the way of new music in here till after I get settled down there. I’ve got plans to build out some better
recording space, there is too much stuff in my office to do any kind of decent recording configuration without having to
play three dimensional Twister while playing.&lt;&#x2F;p&gt;
&lt;p&gt;I do have some old content from a previous iteration of the site which I’ll import. I’ve got a bunch of records left to
archive. So I’ll be bringing those over over time. For now this section will probably be quiet, but eventually I’m
hoping to make my &lt;code&gt;Sesshin&lt;&#x2F;code&gt; style video a more regular occurence.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Move</title>
        <published>2026-08-14T00:00:00+00:00</published>
        <updated>2026-08-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/office/14-aug-2026/"/>
        <id>https://disturbed-circles.com/log/office/14-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/office/14-aug-2026/">&lt;p&gt;It’s quite small for the number of things I try to do in here. 10x15 or so. The basement is really just the whole first
floor of my house, a 20x25 untreated garage and a 40x25 basement floor with about 12x10 cutout for right-angle stairs,
and another 8x17 for mechanical. In this space I am planning to break into sections. The layout is roughly:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ------------------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |            D       I                     .     |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |            I   2   W                     .     |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |            H       I                     .     |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |     1      I=.=D=.=I         4           .  M  |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |            I                             .     |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |            I                             .     |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |            I                             .     |            GARAGE               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |=.=.=D=.=.=.o. . D . . ------------- . D . . . .|                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |                       |  STAIR    |            |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |                       |           |            |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |                       -------|    |   5        D                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |          3            .      |    |            |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |=.=.=.=                .  6               . . . |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; |  SR  |                .                 .  OIL |                                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ---------------------------------------------------D--GGGGGGGGGGGGGGGGGGGGGGGGG-----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#1 - Main Office Area&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#2 - Recording Booth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#3 - Lab&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#4 - Seating&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#5 - Entry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#6 - Pantry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;M  - Mechanical Room&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SR - Server Room &#x2F; Main Panel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; . . .              - stud wall, no sound isolation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=.=.=.=             - stud wall, sound isolation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;`I` when vertical   - stud wall, sound isolation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;D                   - door&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;H                   - half-rack with rear mounted in #2 and front in #1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the rest should be obvious enough&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’ll come back to the garage part another time&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The plan is to have a single-stud false floor under the main office
area, but leave the rest bare concrete. I’ll carpet in the booth, but keep all the electronics out of it mod some
control panels and pedal controls. I play mostly acoustic but I have a kemper that’ll probably be stationed in there, it
currently lives on a half-rack and the plan is to install that so half is in the booth and I can have the frontend
controls for me in there, along with enough controls and monitors to manage the session. There are some water pipes there but I mostly record at night and between that and the sound insulation I can hopefully minimize the noise to acceptable levels.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to keep the easy flow between the lab and the seating area, but I do want them to be separate. I suspect that
door may be a pocket door. There is some storage underneath the stairway, I’m unsure if I want to set up that area to be
availbe to area #6 or #3. The former would require the removal of the sheathing and may not be straightforward to
accomplish, so I’m leaning #3. I want to avoid a 3-6 door&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, as it would greatly reduce the usable configurations of
#6, but I will likely have a passthrough or double-sided cabinet since #6 is going to be where my snacks are. Likely a
minifridge under the stairs; unfortunate to have in the lab, but the most convenient place to locate it for sure.&lt;&#x2F;p&gt;
&lt;p&gt;Area #5 is just general entry and will extend the pantry storage from #6. The OIL tank there is similarly poorly studded
in and takes up a ton of unneeded space because Kevin couldn’t work a square to save his life.&lt;&#x2F;p&gt;
&lt;p&gt;I have two racks to manage all my equipment, they’ll end up in the ‘Server Room’, which is actually &lt;em&gt;not&lt;&#x2F;em&gt; going to be a
studwall. I plan to have two walls-on-wheels that just cover the area but can be fully rolled out of the way when
needed. The design will just be a normal set of stud-walls in a &lt;code&gt;L&lt;&#x2F;code&gt; or &lt;code&gt;U&lt;&#x2F;code&gt; shape (depending on stability), set on
low-profile omni-directional wheels. Maybe a skirt&#x2F;weatherstrip if it’s needed, but ideally there is a slight gap to
encourage some convective airflow&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;#fn-4&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. When I need to work on the rack, just roll it out of the way. The false wall can
still benefit from the heat sink of the foundation of the house, but when I need to work on the rack it’s just ‘slide
the thing out of the way and go to work’.&lt;&#x2F;p&gt;
&lt;p&gt;It also avoids having a very small room that would definitely not meet code.&lt;&#x2F;p&gt;
&lt;p&gt;We plan to move our pool table down here too (I am sure that will be an ordeal covered across many entries), that’ll end
up in #4. Getting it down there may be tricky but fortunately the wall around M is (bad) stud-wall left from the
previous owner (my arch-nemesis, Kevin&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;). I don’t think that stud wall will survive my hatred of it, I’ve already had
to remove about a third of the shitty stud job he did down there. So I can gain a couple feet if the movers need it. The
lower part of that wall doesn’t have a ton of clearance from the furnace, but I can likely re-use my movable-wall idea
here and just have a wall I can roll out of the way when we need to access the area behind it. Gaining access to the
extra space at the cost of a little engineering. That wall could be simpler than the server false wall, since it just
needs to roll out of the way very infrequently.&lt;&#x2F;p&gt;
&lt;p&gt;I may be able to gain a foot of that space back, and could also gain the space at the top of that room as it’s just
covering off the water main and water heater, which are annoyingly separated (honestly the boiler location in this house
makes no sense to me. I blame Kevin, it’s not his fault, but I blame him anyway).&lt;&#x2F;p&gt;
&lt;p&gt;Otherwise that section is probably going to be bare concrete, I’ll fit a couch and TV in there probably, hopefully have
my simracing setup in there as well. I’ll probably put some rugs down. I considered doing more false floors like in
#1 and #2, but concrete-with-a-rug has the advantage of being extremely durable and still pretty comfortable if you
don’t have to stand on it for hours and hours, which is sort of the definitional opposite of what will be done there.&lt;&#x2F;p&gt;
&lt;p&gt;The ceiling is currently open-bay-and-pink-insulation; that will certainly need to change before proceeding, but I think
it’s going to just be a ‘sheet-rock-and-call-it’. I considered doing some amount of drop-ceiling as it would aid in
cable management&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-5-1&quot;&gt;&lt;a href=&quot;#fn-5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but I decided it’d be cooler to run LED strips with the main cable runs (there won’t be too many)
so I can use the LED strip later to identify cables.&lt;&#x2F;p&gt;
&lt;p&gt;Also I can do the blinkenlights with them.&lt;&#x2F;p&gt;
&lt;p&gt;This is basically the plan. I’m at 0% complete, and it’s probably going to take a year or more to get this done, but I
plan to move down there sometime later this year, so the other complexity here is doing this all ‘live’ to some extent.&lt;&#x2F;p&gt;
&lt;p&gt;It’s gonna be a fun project.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Mostly because I have no idea what I’m going to do in there, it’s a mess. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;That is, an X-Y door is a door from section X to section Y, so the 4-5 door is the door between the mechanical
room and stairwell. &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;I’m not an aero guy but my understanding is the heat rising will vent through the top of this false wall, that’ll
need to pull air from somewhere, and pulling it along the cold cement floor sounds like free cooling to me. I plan
to model this space in CAD and maybe I can figure out how to fluid sim it. &lt;a href=&quot;#fr-4-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;Not his real name. &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-5&quot;&gt;
&lt;p&gt;In the sense that I wouldn’t need to &lt;em&gt;see&lt;&#x2F;em&gt; the mess I made &lt;a href=&quot;#fr-5-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>12-AUG-2026</title>
        <published>2026-08-12T00:00:00+00:00</published>
        <updated>2026-08-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/disturbed-circles/12-aug-2026/"/>
        <id>https://disturbed-circles.com/log/disturbed-circles/12-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/disturbed-circles/12-aug-2026/">&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Link GIYF’s atlas page.
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
DNS needs to change for that too
&lt;ul&gt;
&lt;li&gt;Should be giyf.disturbed-circles.com&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
GH
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Repo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
action
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
point at repos everywhere in CI&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
point at paths everywhere locally&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Pages setup&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
DNS for DC generally
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
disturbed-circles.com -&amp;gt; root site&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
giyf.disturbed-circles.com -&amp;gt; atlas&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
other projects in the log section that come from content managed here
&lt;ul&gt;
&lt;li&gt;mostly for projects that don’t really have natural repos of their own.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Project Nobby&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Garden&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Office&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Music section?
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Links to playlists&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Guitar inventory&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Work&lt;&#x2F;li&gt;
&lt;li&gt;Might could harvest some stuff from the old site?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Gehenna
&lt;ul&gt;
&lt;li&gt;A place where i drop ideas that I probably will never get to. I have very many of these.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
FTA needs it’s PDF generated and linked, might be nice to turn the latex -&amp;gt; html at some point
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
PDF Gen&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
PDF Link&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
HTML Gen
&lt;ul&gt;
&lt;li&gt;probably should follow the reorg&#x2F;citation thing. Idea would be to take each env and include citation info
in it directly, then extract to some input format. Later I can add equivalent citation (i.e., where in
Munkres a def appears or something).&lt;&#x2F;li&gt;
&lt;li&gt;not sure if I should keep it as latex as the primary language or extract to a different format&#x2F;convention&lt;&#x2F;li&gt;
&lt;li&gt;aim is Temu nLab, all my notes + cited definitions across my various books. One big map. Queryability would be
nice. Maybe a graphdb – ideally an atlas integration?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;12-aug-2026&quot;&gt;12-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1405&quot;&gt;1405&lt;&#x2F;h2&gt;
&lt;p&gt;I have a big TODO list but I’m starting to whittle it down. I’ve got most of the CI stuff done, but still need to get
DNS wired up. I updated the profile to point to projects which do not yet exist, but all things in time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1449&quot;&gt;1449&lt;&#x2F;h2&gt;
&lt;p&gt;Waiting on tickets leaves lots of time for scutwork. Pages setup done for DC.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1559&quot;&gt;1559&lt;&#x2F;h2&gt;
&lt;p&gt;Good enough for now, I think. HTML Gen for FTA is going to need some thinking about how I notate everything; I’ll
probably need to deeply restructure that repo.&lt;&#x2F;p&gt;
&lt;p&gt;I suspect Gehenna and the other projects and stuff will come after I finish my next big project, which is moving my
office from the current little room I’m in to the basement, where I’ll have much more room to spread things out and set
them up in a way that means I’ll actually work on those projects.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-AUG-2026</title>
        <published>2026-08-10T00:00:00+00:00</published>
        <updated>2026-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/disturbed-circles/10-aug-2026/"/>
        <id>https://disturbed-circles.com/log/disturbed-circles/10-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/disturbed-circles/10-aug-2026/">&lt;h1 id=&quot;10-aug-2026&quot;&gt;10-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1002&quot;&gt;1002&lt;&#x2F;h2&gt;
&lt;p&gt;I have no idea what I’m doing today. Probably worth setting up some kind of DNS stuff for this site, which also means
making the repo and stuff on GH.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Link GIYF’s atlas page.
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
DNS needs to change for that too&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
DNS for DC&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
GH
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Repo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
action
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
point at repos everywhere in CI&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
point at paths everywhere locally&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
other projects in the log section that come from content managed here
&lt;ul&gt;
&lt;li&gt;mostly for projects that don’t really have natural repos of their own.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Project Nobby&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Garden&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Office&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Music section?
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Links to playlists&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Guitar inventory&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
The Work&lt;&#x2F;li&gt;
&lt;li&gt;Might could harvest some stuff from the old site?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Gehenna
&lt;ul&gt;
&lt;li&gt;A place where i drop ideas that I probably will never get to. I have very many of these.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
FTA needs it’s PDF generated and linked, might be nice to turn the latex -&amp;gt; html at some point
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
PDF Gen&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
PDF Link&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
HTML Gen
&lt;ul&gt;
&lt;li&gt;probably should follow the reorg&#x2F;citation thing. Idea would be to take each env and include citation info
in it directly, then extract to some input format. Later I can add equivalent citation (i.e., where in
Munkres a def appears or something).&lt;&#x2F;li&gt;
&lt;li&gt;not sure if I should keep it as latex as the primary language or extract to a different format&#x2F;convention&lt;&#x2F;li&gt;
&lt;li&gt;aim is Temu nLab, all my notes + cited definitions across my various books. One big map. Queryability would be
nice. Maybe a graphdb – ideally an atlas integration?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Work is about to involve a lot of waiting due to a forced reimage, so I want to have some stuff lined up to keep the
tires warm while I wait.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-AUG-2026</title>
        <published>2026-08-10T00:00:00+00:00</published>
        <updated>2026-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/flaming-tongues-above/10-aug-2026/"/>
        <id>https://disturbed-circles.com/log/flaming-tongues-above/10-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/flaming-tongues-above/10-aug-2026/">&lt;h2 id=&quot;1107&quot;&gt;1107&lt;&#x2F;h2&gt;
&lt;p&gt;Thinking about the plan here a bit. I think my aim is just going to be to finish out point set here for now, which is
only another 30 pages or so, then pause to reorganize the notes. I will probably switch to Hatcher to match the course
I’ve been watching for the homotopy stuff. I haven’t been following along the syllabus directly, just watching the
videos, so it’ll be good to have some exercises, and to be honest, I’m kinda just disliking the G&amp;amp;G book a bit. The
authors are inconsistent in some annoying ways (interchanging basis and base freely, for instance), and they also have a
habit of making some intuitive leaps I don’t think are good leaps to take. I don’t think any of it is wrong, just – if
I were formalizing it I think the ratio of lines-of-Lean to lines-of-Proof would be pretty skewed towards Lean.&lt;&#x2F;p&gt;
&lt;p&gt;It has been good for being a pretty &lt;em&gt;dense&lt;&#x2F;em&gt; listing of the various names and structures in point-set though. I feel like
I have a pretty good glossary of definitions now. I like the working mode I’ve come around to of ‘take informal notes on
one thing; formalize another; watch a class; pick two.’ It’s a good pace that’s relatively easy to keep, while feeling
quick. The goal is to build endurance, not speed. Speed only comes through hours spent, endurance comes through
consistently spending them.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>9-AUG-2026</title>
        <published>2026-08-09T00:00:00+00:00</published>
        <updated>2026-08-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/disturbed-circles/9-aug-2026/"/>
        <id>https://disturbed-circles.com/log/disturbed-circles/9-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/disturbed-circles/9-aug-2026/">&lt;h1 id=&quot;9-aug-2026&quot;&gt;9-AUG-2026&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1609&quot;&gt;1609&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve mostly been setting up this site, my intent is to use this version of my &lt;code&gt;LOG.md&lt;&#x2F;code&gt; note-taking to start to
centralize all those &lt;code&gt;LOG.md&lt;&#x2F;code&gt;s here in some sense. This list of posts will be &lt;code&gt;LOG.md&lt;&#x2F;code&gt; for this site + general project
overview&#x2F;thoughts, the individual &lt;code&gt;LOG.md&lt;&#x2F;code&gt;s per project retain their presence so they stay project-local; and then I’m
planning to pull and render all my &lt;code&gt;LOG.md&lt;&#x2F;code&gt;s here as well so they’re legible for me for later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1854&quot;&gt;1854&lt;&#x2F;h2&gt;
&lt;p&gt;That hooked up pretty quickly. LLMs are pretty magic at this kind of thing.&lt;&#x2F;p&gt;
&lt;p&gt;I can pretty easily enumerate projects with a LOG.md and get them pretty seamlessly integrated to the sidebar. At this
point, then, it’s mostly just pixel pushing and at some point getting this stood up on GH and building. Then updates
should be seamless.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1935&quot;&gt;1935&lt;&#x2F;h2&gt;
&lt;p&gt;Did some cleanup of GIYF’s log. Now that I can plan these logs to end up here, I can actually use proper footnotes and
katex and stuff. Nice bonus I hadn’t really thought about. I need to get better at running spellcheck over this stuff
though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2200&quot;&gt;2200&lt;&#x2F;h2&gt;
&lt;p&gt;Pixel pushing, lots of pixel pushing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2239&quot;&gt;2239&lt;&#x2F;h2&gt;
&lt;p&gt;Still TODO:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Link GIYF’s atlas page.
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
DNS needs to change for that too&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
DNS for DC&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
GH action
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
point at repos everywhere in CI&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
point at paths everywhere locally&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
other projects in the log section that come from content managed here
&lt;ul&gt;
&lt;li&gt;mostly for projects that don’t really have natural repos of their own.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>9-AUG-2026</title>
        <published>2026-08-09T00:00:00+00:00</published>
        <updated>2026-08-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/flaming-tongues-above/9-aug-2026/"/>
        <id>https://disturbed-circles.com/log/flaming-tongues-above/9-aug-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/flaming-tongues-above/9-aug-2026/">&lt;h2 id=&quot;2233&quot;&gt;2233&lt;&#x2F;h2&gt;
&lt;p&gt;Started this so it’ll end up in the site eventually. I noticed I’m about halfway through the book and I’m coming close
to the end of it’s point-set material. That lines up in parallel with the Algebraic Topology course I’ve been watching
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;playlist?list=PLOROtRhtegr7DmeMyFxfKxsljAVsAn_X4&quot;&gt;here&lt;&#x2F;a&gt;, which is very good. I know this book
(Gamelin &amp;amp; Green) jumps right into the Fundamental Group&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but that course starts with intuitions about homotopy and
chain complexes and I found that a much nicer way to start.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, that’s going to help out a bunch with reading &lt;em&gt;The Rising Sea&lt;&#x2F;em&gt;, I started taking these notes as a way to
sharpen my topology tools a bit and remind myself of the vocabulary, but I think this is going to be a collection of
notes on a bunch of stuff, maybe do some cross-referencing as I go through. I have a &lt;code&gt;\ggref&lt;&#x2F;code&gt; macro I’ve been using to
just keep general track of where things are, but properly threading these things through and maybe doing some nicer
rendering would be cool.&lt;&#x2F;p&gt;
&lt;p&gt;It’ll be like Temu nLab.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Know is a strong word, I think I remember that it does from like… 25 years ago when I last read it. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>23-JUN-2026</title>
        <published>2026-06-23T00:00:00+00:00</published>
        <updated>2026-06-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/high-tide/23-jun-2026/"/>
        <id>https://disturbed-circles.com/log/high-tide/23-jun-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/high-tide/23-jun-2026/">&lt;h2 id=&quot;0940&quot;&gt;0940&lt;&#x2F;h2&gt;
&lt;p&gt;I had been working off the 2017 draft, which I think I probably grabbed &lt;em&gt;in&lt;&#x2F;em&gt; 2017 and just never came around to work on
until recently. I ordered a print copy. Color me surprised when I saw the numbering misaligned. This means
‘sane-up-to-1.2.&lt;em&gt;’ above should’ve been ‘sane-up-to-1.1.&lt;&#x2F;em&gt;’ which it still is but I misnamed it. :)&lt;&#x2F;p&gt;
&lt;p&gt;I renumbered everything and finished out up to 1.1.B, this required a lengthy sidequest to upgrade atlas to better
encode the approach here. When formalizing text, authors like to pack like-results together and my approach in GIYF was
not scaling well with this. Theorems felt separate even when they were the same item in the book, names were getting
complicated, big pain.&lt;&#x2F;p&gt;
&lt;p&gt;Atlas v2 has a very different structural UI then the version currently used by GIYF, so another ‘big giant refactor’
will be coming soon I suspect.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;High Tide&lt;&#x2F;em&gt; started as a way to get enough context on something I stumbled on while thinking about GIYF’s Line
structure. I &lt;em&gt;think&lt;&#x2F;em&gt; what I found is what Vakil describes in chapter 15, “Line Bundles” – I do not speak enough of the
language to be sure of this, but my idea is roughly matching the description of a ‘Sheaf of Bounded Tanglings’ in my
parlance, and just based on the names I suspect my ‘Tangling’ corresponds to the ‘set of base points’ or ‘base locus’ of
L, the idea is that the lines in the sheaf are the global sections?&lt;&#x2F;p&gt;
&lt;p&gt;I have &lt;em&gt;truly&lt;&#x2F;em&gt; no idea if any of what I just said is correct, but that’s why I’m in the book, it’s a race to Chapter 15
to understand if this is the structure I spotted or if I was looking at something else.&lt;&#x2F;p&gt;
&lt;p&gt;To that end, my plan so far is basically to sprint from Chapter 1 to Chapter 15; with the early chapters receiving a
pretty thorough treatment, and growing more sparse as I get closer to the target chapters, then probably a pretty
thorough work through of Line Bundles. My hope is mostly to gain some technical skill around working with
categories&#x2F;sheaves&#x2F;schemes as a structure; and to verify&#x2F;deny my intuition regarding the ‘sheaves of bounded tanglings’
idea for lines.&lt;&#x2F;p&gt;
&lt;p&gt;I will say, the print version of this book is very nice. I have a softcover on a little 3d printed stand while I’m
working and the print quality is very nice. The cover is colorful in a way that doesn’t scream “Overpriced undergrad
Calculus Book” and is more of a “Someone might mistake this for a book about something that isn’t math.” Which I mean in
the most complementary sense I can.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1034&quot;&gt;1034&lt;&#x2F;h2&gt;
&lt;p&gt;I wouldn’t be surprised if this, too, ends up getting shelved for me to go do some algebra and topology, I have an
&lt;em&gt;Algebra&lt;&#x2F;em&gt; by Hungerford which is &lt;em&gt;not&lt;&#x2F;em&gt; the GTM version that probably covers enough for my purposes and should be pretty
light work. I have another book, &lt;em&gt;Topology: A Categorical approach&lt;&#x2F;em&gt; by Bradely et al, that I’ve worked through part of
before and might be a decent way to extend HT’s Category theory and also rough in some Topology stuff.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-JUN-2026</title>
        <published>2026-06-18T00:00:00+00:00</published>
        <updated>2026-06-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/high-tide/18-jun-2026/"/>
        <id>https://disturbed-circles.com/log/high-tide/18-jun-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/high-tide/18-jun-2026/">&lt;h2 id=&quot;1251&quot;&gt;1251&lt;&#x2F;h2&gt;
&lt;p&gt;I started this a couple days back, aiming to do something a little closer to the Mathlib standard and also get a handle
on the necessary CT to get to sheaves, which I think will play back into the GIYF work around handling Lines&#x2F;Tangles&#x2F;the
like.&lt;&#x2F;p&gt;
&lt;p&gt;So far I really like the book. I’ve taken a couple survey passes over it in the past, and Vakil’s writing style is nice,
and the commitment to a sane numbering system (or, at least, sane-up-to-1.2.*, there is a lot of book here) is pretty
nice. It is going to be a testbed for a new iteration of atlas’ syntax and hopefully should help drive out some more of
its features.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-MAY-2026</title>
        <published>2026-05-27T00:00:00+00:00</published>
        <updated>2026-05-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/27-may-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/27-may-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/27-may-2026/">&lt;h2 id=&quot;1156&quot;&gt;1156&lt;&#x2F;h2&gt;
&lt;p&gt;Working on adding ‘Arrangements’ to the theory. This extends the betweenness syntax to arbitrary ordered lists of
points. In the text, Greenberg uses figures to disambiguate these arrangements, which is unfortunately not really
available to Lean.&lt;&#x2F;p&gt;
&lt;p&gt;The implementation of Arrangements involves a great deal of fiddly list math, and so it’s implementation is largely
Agent-built, but works off the properties proved in Prop 3.3 and its compatriots. The syntax works thusly:&lt;&#x2F;p&gt;
&lt;p&gt;given some set of betweenness statements, you can attempt to prove or reduce another betweenness&#x2F;arrangement by the
following pattern:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; h : A - B - C - D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; organize ABC BCD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, it will close the proof by the simple application of P3.5. However, if you had &lt;code&gt;A-B-C&lt;&#x2F;code&gt; and &lt;code&gt;A-P-C&lt;&#x2F;code&gt;, the
case is ambiguous – there are three possible placements of P (to the left, right, or on top of B), so you get a proof
like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; h : A - P - B ∨ P = B ∨ B - P - C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; organize ABC APC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rcases h &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt; APB | rfl | BPC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;all_goals obvious&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is fine, but I wanted something a little bit cleaner for that as well as for the other branch in 3.5 which results
in 6 different cases to close, all of which are obvious up to some re-arranging &#x2F; deduction of the arrangement.&lt;&#x2F;p&gt;
&lt;p&gt;In some sense this means I didn’t write the proofs for 3.5 really, they fall out of the work the agent did to encode
arrangements; but one of the nice things about Lean and math more generally is that so long as the proof proofs, then we
know the thing works. I don’t necessarily plan to dig in and rebuild this apparatus unless I have to, but I suppose some
human-fidelity is lost in this.&lt;&#x2F;p&gt;
&lt;p&gt;Given that the apparatus is really just ‘bookkeeping applications of Prop 3.3 and topological sorting’, I’m pretty
alright with that state of affairs; but wanted to be clear.&lt;&#x2F;p&gt;
&lt;p&gt;The syntax I settled on was:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;arranging &amp;lt;hypos&amp;gt; [into &amp;lt;rcases-like-breakdown&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;. proof-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt;-cases-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;-necessary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This takes the given hypos and optionally a naming cluster like &lt;code&gt;rcases&lt;&#x2F;code&gt;, then it attempts to &lt;code&gt;obvious&lt;&#x2F;code&gt; off any produced
goals before finally returning a minimal set of nonobvious cases. Under the hood this uses the &lt;code&gt;organize&lt;&#x2F;code&gt; apparatus, but
arranged more like the &lt;code&gt;distinguish&lt;&#x2F;code&gt; tactic, which uses available proofstate to try to weed through simple goals. I’ve
sort of mentally decided that anything that just needs to sweep the proofstate once is fundamentally not expensive and
well worth doing proactively. So far compile times haven’t suffered to the point of being noticable, like with prior
experience with &lt;code&gt;tauto&lt;&#x2F;code&gt; and &lt;code&gt;simp&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As part of it, I also implemented &lt;code&gt;CoeDep&lt;&#x2F;code&gt; (value-dependent coercion) for arrangements down to betweenesses; which means
they are drop-in wherever a Betweenness is allowed. This makes it pretty gentle to use overall. Derive the full
arrangement then drop it into place. The mechanism here is good old &lt;em&gt;macros&lt;&#x2F;em&gt;, like the C-preproc kind (except done with
elab). This generates a finite suite of instances to do each coercion for each finite arrangement size. We can’t
natively support arbitrary arrangements without introducing a tactic, which would ruin the drop-in ability, but
practially arrangements of up to 7 points are supported for about ~2s of compile time over the n=5 case. The book never
gets above 5 points in a line from my brief survey, so should be fine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1602&quot;&gt;1602&lt;&#x2F;h2&gt;
&lt;p&gt;Currently renaming all of the lemmas&#x2F;exercises and reorganizing again. LLMs are a godsend for fiddling with this kind of
thing.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>24-MAY-2026</title>
        <published>2026-05-24T00:00:00+00:00</published>
        <updated>2026-05-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/24-may-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/24-may-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/24-may-2026/">&lt;h2 id=&quot;1219&quot;&gt;1219&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been doing a series of largely mechanical refactorings and restructurings. The main thrust of which is a typed
heirarchy for line-parts (which is not &lt;em&gt;exactly&lt;&#x2F;em&gt; what I wanted, but is a significant improvement over the prior state).
As well as trying to capture what Greenberg considers ‘obvious’ in a tactic (creatively named &lt;code&gt;obvious&lt;&#x2F;code&gt; as well), which
I’m hoping will leverage &lt;code&gt;atlas&lt;&#x2F;code&gt; at some point to do a phased ‘intuit like Greenberg’ automated theorem proof attempt.
The aim isn’t necessarily to replace every place Greenberg calls a ‘clearly X holds’ or ‘obviously Y is true’ with this,
but most of the cases where he does, the result is really trivial and should be inferred without argument. &lt;em&gt;Sometimes&lt;&#x2F;em&gt;
(as in Pasch’s ‘A and B are clearly not on L’) the argument isn’t necessarily so obvious, though, and these are
interesting places where Greenberg’s intuition might’ve been making ‘leaps of faith’ which should have been justified
more thoroughly. In the end I hope to capture all the little intuitive, subconscious arguments that Greenberg used and
develop something like a ‘If Greenberg were arguing here, he would consider this subtextually true &#x2F; true without
argument’ as a sort of research artifact.&lt;&#x2F;p&gt;
&lt;p&gt;The process of getting there has been an interesting application of LLMs in this space.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, the process has been one of “Let’s build up a structure that ties into the existing mathlib machinery to
represent lineparts.” This involved fighting with Coe and the elaborator and some other syntax fighting. I estimate it
would’ve taken a few weeks of solid effort to get done, Claude finished in a day. That’s an honest-to-goodness savings
on work I really didn’t want to do. Most of it was weedy, mechanical shit of wiring up and rewriting after each
iteration to get the corpus compiling. I’m barely 20% through the book and have about 4KLOC of lean, most of which are
lemmas-in-anger, so being able to mechanically replace a component like that was a very legitimate value add.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t think, however, it would’ve come up with the structure on it’s own. It was struggling to understand &lt;em&gt;why&lt;&#x2F;em&gt; I
cared about making these parts flow together; and frequently suggested some flavor of “We’re at the limits of what Lean
can do.” until I reminded it of some other extension we could try. We did eventually hit the limit (there is an
irreducible type ascription necessary in some few cases of intra-type equality comparisons), but it was only after
blowing past a few others that the machine thought existed.&lt;&#x2F;p&gt;
&lt;p&gt;Once the apparatus was built and installed, the really interesting step happened. The &lt;code&gt;obvious&lt;&#x2F;code&gt; tactic was able to close
out entire lemmas that were proved before, resulting in a significant reduction in the total surface area of nontrivial
theorems. If a proof is just &lt;code&gt;:= obvious&lt;&#x2F;code&gt;, then every &lt;code&gt;ref&lt;&#x2F;code&gt; to that theorem can be replaced by &lt;code&gt;obvious&lt;&#x2F;code&gt; to drop one
layer of indirection. So I instructed the machine to do the following:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Go to each lemma, replace it by &lt;code&gt;obvious&lt;&#x2F;code&gt; and see if it closes, if it does, mark it for inlining.&lt;&#x2F;li&gt;
&lt;li&gt;Go to each marked lemma and inline it, replacing all of it’s occurences with a &lt;code&gt;obvious&lt;&#x2F;code&gt;. If the inline fails, raise a flag&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;No flags were raised, and a bunch of lemmas (about a dozen) dropped away. Crucially, though, some of them &lt;em&gt;didn’t&lt;&#x2F;em&gt; and
in fact, &lt;em&gt;couldn’t&lt;&#x2F;em&gt;, these were the core underlying ‘obvious’ facts that Greenberg takes without proof, but are
necessary in formalization. I landed on something very neat, by ‘shaking the tree’ to try to refactor proofs to use more
of Greenbergs intuition. I got proofs back that were closer to the book, but also got proofs that were irreducible and
unstated by the author, meaning they represent some fundamental component of his intuition. They were required by
&lt;code&gt;obvious&lt;&#x2F;code&gt; to close the other goals.&lt;&#x2F;p&gt;
&lt;p&gt;It also led me down this other interesting path adjacent to but distinct from other automatic theorem prover tactics.
Consider the humble &lt;code&gt;tauto&lt;&#x2F;code&gt;, which has this problem:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given an arbitrary type with universal and existential quantifiers, a proofstate full of hypotheses of arbitrary
shape (also with various quantification) and a corpus of theorems about as wide as &lt;code&gt;@[simp]&lt;&#x2F;code&gt;’ll get you, resolve the
goal.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;There is no context on what kinds of theorems there are, no insight into the relevant corpus of math, no ability to
filter or prune anything. It’s a really hard problem, and people have come up with extremely clever ways to optimize it,
but math isn’t a ‘prove any theorem’ game, it’s a ‘prove &lt;em&gt;this&lt;&#x2F;em&gt; theorem’ game. When proving, one has the &lt;em&gt;context&lt;&#x2F;em&gt; to
rely on. I know I’m proving theorems in synthetic geometry here, I don’t need to consider calculus or number theory
(yet). I can limit my scope much more aggressively if I look at the proof goal and see it involves intersections, I can
make more complicated, geometry-local arguments that wouldn’t necessarily translate wholesale to other fields. In a
sense, the progress in the unconstrained world is stymied &lt;em&gt;by&lt;&#x2F;em&gt; the lack of constraint. It is much harder to do math if
you don’t specialize.&lt;&#x2F;p&gt;
&lt;p&gt;So &lt;code&gt;obvious&lt;&#x2F;code&gt; is sort of a start towards a specialized “geometry” tactic, but it’s even more specific than that, it’s
&lt;em&gt;Greenberg&lt;&#x2F;em&gt; that I’m modelling here. It’s a &lt;em&gt;specific&lt;&#x2F;em&gt; intuition (as captured by the book and my formalization of it,
which means it is not without some bias), and I think that’s pretty cool. I can imagine building up a little library for
designing these bespoke tactics per book. Then when the time comes to prove something new I can throw a corpus and it’s
corresponding intuition at it for the low cost of translating it to the language that tactic understands.&lt;&#x2F;p&gt;
&lt;p&gt;I’m sure the idea isn’t novel, but it is fun, and blends nicely with the &lt;code&gt;atlas&lt;&#x2F;code&gt; thing I’ve worked on. I should be able
to incorporate some ranking&#x2F;searching directly in the graph, which means I can have the structure inform how best to use
the structure (a theorem with a high pagerank after a specific filter is applied might be a good way to search corpii
efficiently).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-MAY-2026</title>
        <published>2026-05-18T00:00:00+00:00</published>
        <updated>2026-05-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/18-may-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/18-may-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/18-may-2026/">&lt;h2 id=&quot;1454&quot;&gt;1454&lt;&#x2F;h2&gt;
&lt;p&gt;Time to talk about Agents and LLMs and this codebase.&lt;&#x2F;p&gt;
&lt;p&gt;First things first, all the math is me. No agents involved in the primary proving of anything beyond the occasional
‘remind me how this syntax works’. I want to be clear that humans are doing the math here, not agents.&lt;&#x2F;p&gt;
&lt;p&gt;Second, the &lt;code&gt;distinct&lt;&#x2F;code&gt; and &lt;code&gt;collinear&lt;&#x2F;code&gt; syntaxes, as well as most of the ‘small’ syntax tweaks (&lt;code&gt;obvious&lt;&#x2F;code&gt;,
&lt;code&gt;by_exhaustion&lt;&#x2F;code&gt;, etc) are mostly me, similar to the above, with the occasional ‘add the six other cases following the
same pattern’ level prompting. Edits, but small and proscribed.&lt;&#x2F;p&gt;
&lt;p&gt;Third, &lt;code&gt;atlas&lt;&#x2F;code&gt;, Atlas is almost entirely LLM-coded. I guided it through what I wanted the parser to do and what kind of
information I wanted to record. I also had it mechanically convert all the various callsites to use the system and
generate some ‘pithy’ names for things.&lt;&#x2F;p&gt;
&lt;p&gt;Now let’s talk about why I think this is okay, as these tools are controversial in a way that feels hysterical.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pneumatic-nailers-and-table-saws-lathes-and-agents&quot;&gt;Pneumatic Nailers and Table Saws, Lathes and Agents&lt;&#x2F;h3&gt;
&lt;p&gt;The Pneumatic Nailer, “Nailgun,” was introduced in 1950. It was designed to speed up the construction of houses by
making floor and wall sheathing much simpler. Instead of manually hammering things, you’d use instead a bulky,
unreliable, expensive and power-hungry pneumatic nailer to do the work that a journeyman carpenter could do in about the
same amount of time as a journeyman carpenter could do it with a hammer and practice. You can imagine how large house
building companies would embrace this technology, even as their more seasoned workers hated using it. They were
dangerous, the broke a lot, they cheapened the trade and reduced the skill floor. Some punk kid on the jobsite could
pick up a nailgun on day one and be installing subfloor, where was the craftsmanship, where was the quality? Are we just
gonna &lt;em&gt;not build good houses anymore?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;No one thinks using a nailgun isn’t homebuilding anymore. No one thinks that a nailgun-based home construction technique
builds a materially &lt;em&gt;worse&lt;&#x2F;em&gt; home. They might argue homes are worse today than in the past, but as someone who has been
around old and new construction my whole life; it’s always been about as bad as it’s always been.&lt;&#x2F;p&gt;
&lt;p&gt;Table Saws probably were similar. No more need for proper form and structure; no need to practice technique. Just
measure twice, cut once, make sure you know how to avoid kickback.&lt;&#x2F;p&gt;
&lt;p&gt;I heard a story once about Norm Abrams, the host of &lt;em&gt;New Yankee Workshop&lt;&#x2F;em&gt; and a personal hero. He got his first
on-screen job after having worked as a journeyman carpenter on a job for the producer of &lt;em&gt;This Old House&lt;&#x2F;em&gt; before it came
on the air. In the late ’70s, the use of power tools would’ve been common, but it wouldn’t’ve necessarily been the only
kind of homebuilding, and while a radial-arm probably would’ve been the standard power saw on a jobsite, it is easy to
imagine such a thing leading some to wastefulness and carelessness. It’s so &lt;em&gt;simple&lt;&#x2F;em&gt; to make a cut, it’s so &lt;em&gt;easy&lt;&#x2F;em&gt; to
get it to the right size. Norm got the job because of his efficiency with the tools at hand, and the rest is TV history.&lt;&#x2F;p&gt;
&lt;p&gt;In my shop, I have a woodlathe. A lovely Grizzly that spins large hunks of frequently unstable wood by means of various
chucks and mounts and a big ass electric motor on the back. I can twirl a hunk of hickory at 2500RPM and stick a tool
into it. It is by far the most dangerous tool I own; it actively wants to kill me, it wants to see me dead, it wants it
to hurt the whole time. In the old days, a lathe would’ve been made of wood and rope, and powered by a ‘spring pole’ –
a green stick that would reciprocate the work back and forth in time with your foot movements. It was safer than my
lathe, slower too. I imagine the introduction of the electric, motor-driven lathe might’ve left spring-pole enthusiasts
worried about the craftsmanship, the reduction of the skill floor, the worsening of their trade.&lt;&#x2F;p&gt;
&lt;p&gt;But I can turn beautiful work on my lathe, even though it wants to kill me, even though it is more dangerous. To be
honest, I’m not sure I could produce the same quality of work on a springpole, even if I started with it. There are
limitations inherent in the tool. The reciprocation means different techniques are available and different constraints
are in place.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tools-and-weapons&quot;&gt;Tools and Weapons&lt;&#x2F;h3&gt;
&lt;p&gt;My path through LLMs has been pretty bouncy. I started with the same curiousity as everyone. I tried GPT4 and early
copilot-style autocomplete. I thought it was cool. I used it in &lt;code&gt;hazel&lt;&#x2F;code&gt; for a bit, but rapidly found, like most people,
that the code was poor quality and not much better than cut-pasting. I spent a lot of energy cleaning up that mess, and
Hazel is better for it, but almost none of that code remains[1]. As I learned more about the ethical… well let’s just
go ahead an call it what it is instead of euphemizing it as an ethics problem. The big “AI” companies committed the
largest act of copyright infringement to have ever been done. It makes Napster look like shoplifting. It was simple
larceny. They stole petabytes of art, literature, and music; packaged it, and sold it as if it were theirs. Depriving
the original creator of the value of their labor. This is unconscionable and wrong in a way that I’m comfortable
thinking of as Sinful, with all the weight applied to it as I would have when I was an Evangelical Nationalist Scumbag.&lt;&#x2F;p&gt;
&lt;p&gt;It was simply evil behavior, performed by evil men (it is always men, it seems), and they should be shamed, pilloried,
and launched into the sun for having done it. These facts, and the existential threat to my job and career, the threat
to my family by dint of that, and all the myriad anxieties the “AI” tulip craze that was and is and will continue to
spiral until crashing – as it inevitably will – led me towards a sort of deep hatred for the technology. It wasn’t
until I realized how I started talking about it that I understood the mistake I was making.&lt;&#x2F;p&gt;
&lt;p&gt;I started calling LLMs “the False Prophet,” I thought of them with irrational anger and disgust. I transferred the shock
and horror and dissapointment with the actions of their creators with the tool itself. I was &lt;em&gt;mad&lt;&#x2F;em&gt; about it. Then I got
tagged by my therapist, “It sounds like you’re pretty heated, Joe. But don’t you always say, ‘it’s a poor craftsman that
blames the tool?’”&lt;&#x2F;p&gt;
&lt;p&gt;Here’s the reality we live in, folks, the deed is &lt;em&gt;done&lt;&#x2F;em&gt;. We can mourn the past, but not return to it. We are &lt;em&gt;here&lt;&#x2F;em&gt;
now, &lt;em&gt;alea iacta est&lt;&#x2F;em&gt;. The constant cry of ‘WeLl NoOnE iS mAkInG yOu UsE iT!’ falls on deaf ears the moment my families
livelihood is in peril. You are right, no one is &lt;em&gt;making&lt;&#x2F;em&gt; me do it, just like how no one will &lt;em&gt;make&lt;&#x2F;em&gt; food appear on the
table. There is no ability for me to respond against the crushing weight of the machine that has been so long built by
capitalists and bastards (sorry to repeat myself), so we can have no responsiblity other than to ask now, “What do we
fucking &lt;em&gt;do&lt;&#x2F;em&gt; with the monster they made?” “Is it the monster’s fault that Frankenstein made it?” “Should we kill it simply
because its creation was abominable to us?” “Isn’t that cruelty too?” “Isn’t that wrong?”&lt;&#x2F;p&gt;
&lt;p&gt;I don’t mean to say we would be killing a literal, living thing, but I refuse the notion that a tool itself is ethical
or not. I suppose, if pressed, I’d have to say that the argument that has always seemed strongest to me about gun
control is the ‘Guns don’t kill people’ argument. It’s simply correct, guns &lt;em&gt;don’t&lt;&#x2F;em&gt; kill people, it’s irrefutable in
some sense. Whether through intent, negligence, or mistake, it requires action on the part of &lt;em&gt;someone&lt;&#x2F;em&gt; to make the tool
into a weapon and for that weapon to harm another[2].&lt;&#x2F;p&gt;
&lt;p&gt;I don’t want LLMs to be weapons, but the only way to make them &lt;em&gt;not&lt;&#x2F;em&gt; weapons is to find out how to &lt;em&gt;use them like
tools&lt;&#x2F;em&gt;. I can’t assign ethical or moral value to the machine-what-is-made. I can only try to understand the effect of
its existence and how I can use it to find ways to be kind.&lt;&#x2F;p&gt;
&lt;p&gt;I have a lot of thoughts on how that might be done, but the first step is to learn how to use the tool in ways that feel
like I’m producing something that might actually benefit people sufficiently to justify the cost of the tool. I have
spent some months now unpacking and understanding this technology. I think it has broad, mostly unexplored uses, uses
that could legitimately benefit more than the cost. I think that there are ways to get these tools to produce good
output that can be genuinely useful and improve peoples lives. If you don’t, cool, don’t use the tools, but I will
accept criticism of my use in precisely one form, &lt;code&gt;&amp;amp;&amp;gt; &#x2F;dev&#x2F;null&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;[1] I caveat only because I truly don’t remember which code was generated anymore, almost all of it has been touched at
this point though so it’s probably gone.&lt;&#x2F;p&gt;
&lt;p&gt;[2] This not to say that it is a good enough argument to justify all the things people try to use this to justify, we
still need gun control for lots of good reasons, but it’s complicated by the fact that this is, ultimately, a pretty
good fact the gun control advocate needs to reckon with.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-is-good-code&quot;&gt;What is good code?&lt;&#x2F;h3&gt;
&lt;p&gt;Once I started trying these tools I started to ask a new kind of question, not “Is this good code?”, nor “Can I make
this produce good code?”, but “What is good code?”&lt;&#x2F;p&gt;
&lt;p&gt;In mathematics, we focus on properties. We might say that a line has the property of being defined by two distinct
points; and conversely that two distinct points have the joint-property of defining a unique line; and so on. I started
to ask “What are the properties of ‘good’ code?”&lt;&#x2F;p&gt;
&lt;p&gt;I was easy to enumerate many &lt;em&gt;features&lt;&#x2F;em&gt; of good code. It’s well-factored, it’s well-tested, the tests are resilient and
easy to understand and change. Really the whole codebase should be well documented and easy to understand and change. It
should be well-specified and it’s edge cases well tested. I should be able to trust the code and when my expectations
about it’s output fail I should be able to easily identify, isolate, reproduce and change the code to address the
failing.&lt;&#x2F;p&gt;
&lt;p&gt;There was a theme developing, it’s not hard to see, good code is:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Easy to understand&lt;&#x2F;li&gt;
&lt;li&gt;Easy to change&lt;&#x2F;li&gt;
&lt;li&gt;Well specified and well tested.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;None of those things constrain the &lt;em&gt;shape&lt;&#x2F;em&gt; of the code, or its implementation, the only constrain what the code &lt;em&gt;does&lt;&#x2F;em&gt;
and what you can &lt;em&gt;do to it&lt;&#x2F;em&gt;. Does it matter how I answer those questions? If I can read a good codebase, let’s take
&lt;code&gt;ripgrep&lt;&#x2F;code&gt; as an example, I can see structure present there, I can build up a mental model. I might have to spend a bunch
of time learning the machine’s innerworkings, but the code is &lt;em&gt;good&lt;&#x2F;em&gt;, it is &lt;em&gt;well factored&lt;&#x2F;em&gt; and &lt;em&gt;precise&lt;&#x2F;em&gt;, it minimizes
mental load as much as it can for being a complex tool with many precision engineered parts.&lt;&#x2F;p&gt;
&lt;p&gt;It is easy to understand (relative to your understanding of Rust and the techniques involved), it is easy to change
(because it is well-factored, and assuming you have a good existing understanding of the design of the system), and it
is well specified and tested. It is Good Code (tm).&lt;&#x2F;p&gt;
&lt;p&gt;If I think about the &lt;code&gt;Atlas&lt;&#x2F;code&gt; thing I just built, it is also easy to understand – if I have a question about the
structure I can ask the LLM, I can get a line-by-line walkthrough if I want. It is &lt;em&gt;much&lt;&#x2F;em&gt; more adept and API-aware than
me, and while it can often write code I don’t immediately understand, there isn’t any part of it I am &lt;em&gt;incapable&lt;&#x2F;em&gt; of
understanding, and with sufficient curiousity I can learn the deep parts fo the system just as before.&lt;&#x2F;p&gt;
&lt;p&gt;Arguably, it’s &lt;em&gt;easier&lt;&#x2F;em&gt; to change than a handrolled implementation, I just have to precisely describe what I want. Often
that means giving it instructions about how to rewire the machine’s internals (not the oft-assumed “write me a tool”
prompt, rather a “adjust how the syntax is parsed here to use this API in this way.” It’s certainly less typing than
before, and as someone who spends most of their waking life typing things into this infernal box, less typing is a
&lt;em&gt;massive&lt;&#x2F;em&gt; win for my physical and mental health.&lt;&#x2F;p&gt;
&lt;p&gt;It’s lean, well-specified here means ‘comes with mathematical proof’, but even in other languages you can pretty easily
build up a comprehensive test suite; optimize it; measure its coverage; mutant and fuzz test it – the incremental cost
of testing your code is now nearly zero, the incremental cost of changing it is zero. The places where we have trouble
are in getting insight into the internal, abstract structure of the code. Before the bottleneck was &lt;em&gt;writing&lt;&#x2F;em&gt; code, now
the bottleneck is &lt;em&gt;understanding&lt;&#x2F;em&gt; code and its structure.&lt;&#x2F;p&gt;
&lt;p&gt;So, no matter the implementation, if I can answer those three questions in the affirmative, isn’t whatever I have – by
definition – good code? It is not &lt;em&gt;pretty&lt;&#x2F;em&gt; code – I don’t like the look of LLM-generated code more than most people,
but in the fully ‘vibecoded’ ecosystem, the reality is the codebases are perfectly cromulent, so long as I don’t really
read the code too deeply. The skeptics among you clutch their keyboards and say “But how do you know it works?” To which
I reply, “My test suites are more thorough than anything I could write on my own, I have every possible path covered and
specified, I built tests which test my tests to ensure the tests are testing what they are supposed to test. I have
mutation testing, fuzz testing, property testing, unit and integration tests, I test in situ, I test end to end. Some of
this stuff is &lt;em&gt;literal, mathematical proof&lt;&#x2F;em&gt; What more could you want to prove it to you? How much do you have? Why
should I trust &lt;em&gt;your&lt;&#x2F;em&gt; software? Do you have formal proof it works?”&lt;&#x2F;p&gt;
&lt;p&gt;The refrain of “It’s not good code” relies on a notion of ‘good code’ that is optimized not for what good code &lt;em&gt;is&lt;&#x2F;em&gt;, but
for what &lt;em&gt;good code is for a handwritten, human codebase&lt;&#x2F;em&gt;. The issue is that we have mistaken the &lt;em&gt;limitations of our
tools&lt;&#x2F;em&gt; for the &lt;em&gt;indications of quality&lt;&#x2F;em&gt;. We are overgrown monkeys doing mathematics on specialially arranged rocks; we
have designed practices to accomodate for our weaknesses; but those practices are, themselves, no different than the
hours you’d spend hucking a hammer at a nail installing sheathing and subfloor; they’re no different than the time spent
structuring your body to properly cast and return a handsaw. We have new tools now, we need new practices, and that
means new understanding of what good looks like in a new context.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not saying every project is a vibe project. Indeed, this is an example of a project which is emphatically &lt;em&gt;not&lt;&#x2F;em&gt; a
vibe project. Why? Because the point of this project is for me to engage the math and build something mostly by hand.
LLMs enter into it more like a orbital sander. Is hand sanding “better”? No, it’s different, it leaves a different
finish, people may be able to spot the tell-tale circular pattern, but it’s not &lt;em&gt;better&lt;&#x2F;em&gt; to sand by hand, it’s not
&lt;em&gt;worse&lt;&#x2F;em&gt; to sand by machine. It’s not &lt;em&gt;better&lt;&#x2F;em&gt; for me to manually replace every &lt;code&gt;theorem &amp;lt;name&amp;gt; : &amp;lt;statement&amp;gt; := by &amp;lt;proof&amp;gt;&lt;&#x2F;code&gt;, an LLM can do that work for me in much less effort (though not much less time, if I’m honest); it doesn’t
detract from the product to automate away those sorts of changes, and indeed it allows them much better and richer
tooling later.&lt;&#x2F;p&gt;
&lt;p&gt;My point is simply: If you are reacting to these tools with anger at the loss of the old ways of doing things, I feel
you, but you don’t get to uninvent the nailgun. You can’t un-table the saw. The only question is ‘do these things have
any use at all’ and ‘is the juice worth the squeeze’? At this pint, I think at this point, I can answer at least the
former, and I’m beginning to see the answer to the latter too.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-the-use&quot;&gt;What’s the use?&lt;&#x2F;h2&gt;
&lt;p&gt;The uses of LLMs in this repo have been stated, but at a higher level, I use LLMs in the following ways to good effect:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mundanity&quot;&gt;Mundanity&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;pure-shameless-vibecoding&quot;&gt;Pure, Shameless Vibecoding:&lt;&#x2F;h4&gt;
&lt;p&gt;Ask for a thing, recieve a buggy, halfworking thing that mostly just looks the part. This is entirely for the purpose of
candy. A cardboard version of a product is a useful thing for me. I am not skilled in visualizing the final product. I
may be aphantasic[3], but in any case, being able to get a cardboard cutout of a thing to look at and talk about with
people is extremely useful.&lt;&#x2F;p&gt;
&lt;p&gt;[3] I don’t know, I’ve never been not me, so I can’t tell you whether I’m seeing more or less in my ‘mind’s eye’, I can
say that I have always assumed that to be much more metaphor than other people I know&lt;&#x2F;p&gt;
&lt;h4 id=&quot;data-gathering-and-scutwork&quot;&gt;Data gathering and scutwork.&lt;&#x2F;h4&gt;
&lt;p&gt;There is a large class of things for which I need the product of a process but have no interest in its performance &#x2F; I
do not stand to gain a skill I want from practice there. This ranges from truly mundane questions like finding facts
about pricing or API shape, to researching bugs in my editor configs. I cannot express to you how little I care about my
dotfiles. I simply couldn’t give a shit if they look nice or are wellmaintained. I want my editor to always do exactly
what I want, I don’t care who maintains it or how, I don’t care about it at all, it just has to always do exactly what I
expect and otherwise be a transparent thing. The most common cause of project abandonment for me is &lt;em&gt;not&lt;&#x2F;em&gt; an overhard
problem, it is always the same thing. Some externality – editor config, testing&#x2F;hosting infra, etc – gets in the way
of me continuing to work on the interesting part of the project. WLOG, let’s call that class of work scutwork.&lt;&#x2F;p&gt;
&lt;p&gt;Scutwork is a necessary evil, with greater emphasis on the ‘evil’. It is weapons-grade boredom, and the answer to this
has always been “Use this framework, set it up once, and try not to think about it.” or “Just fucking do it.”&lt;&#x2F;p&gt;
&lt;p&gt;Fuck every square millimeter of that. I don’t want to maintain that shit, and frankly I don’t know anyone who actually
does. If you are one such person. I think you’re weird (complementary), and I do not aspire to be like you. I’m here to
do math, not convince Neovim to stop being so fucking stupid.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;targeted-refactors-draw-the-rest-of-the-fucking-owl&quot;&gt;Targeted Refactors &#x2F; Draw the rest of the fucking Owl&lt;&#x2F;h3&gt;
&lt;p&gt;Prop 3.3 in this repo has a case where LLMs helped greatly with the math. There is a common, underlying argument in that
setup for the Line Separation property (3.4), and I could see it, but extracting it from the haze of specific variables
was really, really hard. I could smell it, but I couldn’t hunt it down. Excitingly, this intuition came first from the
code, and I aligned it with the intuition in the math. It was a delightful moment when I linked the two things together
and felt the intuition in the math spill onto the code and the real &lt;em&gt;power&lt;&#x2F;em&gt; that Lean might offer was spread out. Then I
realized how &lt;em&gt;fucking awful&lt;&#x2F;em&gt; it was going to be to extract that common argument, so I put down the project for 2 months
and dealt with my anger around LLMs.&lt;&#x2F;p&gt;
&lt;p&gt;Then I asked Claude to highlight the extractable argument after describing what I saw, it made a suggestion, I verified
it, did the proof, and then ported it back into the proof. From there it was much, much simpler to complete the other
branches of the proof complex, and thus 3.3 was closed.&lt;&#x2F;p&gt;
&lt;p&gt;In another project, I inherited a pile of 50 or so jenkins pipelines. I do not know groovy, but I can hack together
something that is almost valid groovy and expresses the intent accurately. I left the code littered with little todos
and then told Claude to paint inside the lines I left it. Twenty minutes later I had the rest of the fucking owl, and
all my pipelines ported. I genuinely would have taken days or weeks to do that alone.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t need or want to be a groovy expert. I don’t need or want to spend hours meticulously adjusting incantations to
satisfy Lean. I want to spend my mental energy on the overall CI ecosystem. I want to spend my time in the Math. LLMs
let me be efficient with &lt;em&gt;what skills I’m reinforcing&lt;&#x2F;em&gt; and &lt;em&gt;what I delegate to someone (or something) else&lt;&#x2F;em&gt;. If I had,
at my disposal, an army of grad-students and interns and junior engineers, it is the class of work I would send them off
to do not because I thought it would improve their ability to do their main jobs, but because I would not like to do
that work and I have an army at my behest. I did not have such an army before, now I do. Now if I acquire such an army,
I can send &lt;em&gt;them too&lt;&#x2F;em&gt; on missions of &lt;em&gt;actual&lt;&#x2F;em&gt; import to their &lt;em&gt;actual&lt;&#x2F;em&gt; goals.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-much-juice&quot;&gt;How much juice?&lt;&#x2F;h2&gt;
&lt;p&gt;LLMs, Agents, “AI”, whatever you prefer to call it, it is not &lt;em&gt;useless&lt;&#x2F;em&gt;, it’s not perfect, it’s a machine that guesses,
and guesses are not useless things. You &lt;em&gt;can&lt;&#x2F;em&gt; get these tools to produce good code (under both understandings), though
human-good code is much more difficult to achieve, it is possible to do so with sufficient prompting and oversight. In
this project already it has more or less covered a month or two of weekends worth of scutwork that, frankly, probably
would’ve killed this project.&lt;&#x2F;p&gt;
&lt;p&gt;Is this project valuable? It certainly is valuable to me. It feels good to work on this, I like that I found a way to do
&lt;em&gt;real&lt;&#x2F;em&gt; math again, not the idle pining for a life not lived, not the silly doodles of differential equations in
meetings; but real, honest-to-goodness math.&lt;&#x2F;p&gt;
&lt;p&gt;Is it valuable to others? I don’t know, I like to think Atlas will be a generally useful thing, and maybe someone,
someday will ready the body of GIYF or tour through the Atlas site and learn something useful. I don’t know that what
I’m doing is &lt;em&gt;“Good”&lt;&#x2F;em&gt;. I’m not sure that &lt;em&gt;Good&lt;&#x2F;em&gt; is even a meaningful concept so much as a pleasant fiction – a lie to
children – that we tell to make ourselves feel better about a reality that is fully indifferent to us at all levels,
times, and spaces we inhabit. I can’t tell you to like this work, I can’t tell you to accept it, or even to not hate it.
If my use of agents bothers you, I have empathy for you, but for me – their use lets me do the things I want to do in
life, and none of us asked to be here, or be thrust into all this. For me, I’m going to use the tools available to me in
the most responsible and efficient way I can. I promise I won’t act carelessly and wastefully in their use, and I won’t
treat them with the kind of flippancy that many do. If that is insufficient for you, I’ll give you the same response I
put in a recent commit removing the anti-LLM canary.&lt;&#x2F;p&gt;
&lt;p&gt;“I do not care.”&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>13-MAY-2026</title>
        <published>2026-05-13T00:00:00+00:00</published>
        <updated>2026-05-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/13-may-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/13-may-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/13-may-2026/">&lt;h2 id=&quot;1600&quot;&gt;1600&lt;&#x2F;h2&gt;
&lt;p&gt;I spent a bit of time refactoring 3.3, extracted a helper, had a small think about how much to tweak the arguments
Greenberg made for Lean convenience. I went with a hybrid approach, some theorems will get refactored for my own sanity,
some will be kept all inline so it is clear which chunks of lean correspond to which statements. I think that will help
identify where Greenberg is making intuitive leaps that are worth examining closely, while still leaving me with tools
ready for proving other things.&lt;&#x2F;p&gt;
&lt;p&gt;I left this project for a bit while I worked on other things, but I’m going to come back to it now. I’m pleasantly
surprised at how well Lean has remained in my brain despite a couple months of hiatus.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>5-MAR-2026</title>
        <published>2026-03-05T00:00:00+00:00</published>
        <updated>2026-03-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/5-mar-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/5-mar-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/5-mar-2026/">&lt;h2 id=&quot;1316&quot;&gt;1316&lt;&#x2F;h2&gt;
&lt;p&gt;Finished 3.3, there are some corrolaries to wind up, but the main bulk is done. The proof is &lt;em&gt;very&lt;&#x2F;em&gt; long and pretty
nasty, so it probably needs an intermediate or ten to clean it up.&lt;&#x2F;p&gt;
&lt;p&gt;I started thinking about a couple tasks I want to do:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alignment&#x2F;Concurrence – a generalization of the &lt;code&gt;collinear&lt;&#x2F;code&gt; condition to accept an arbitrary set of points,
convertible from &lt;code&gt;collinear&lt;&#x2F;code&gt;, but covers all the line equality constraints automatically.&lt;&#x2F;li&gt;
&lt;li&gt;Separating &lt;code&gt;Theory&lt;&#x2F;code&gt; a bit more, creating namespaces for &lt;code&gt;Ray&lt;&#x2F;code&gt;, &lt;code&gt;Segment&lt;&#x2F;code&gt;, etc. Cleaning up naming, and ideally
getting &lt;code&gt;aesop&lt;&#x2F;code&gt; tags set up?&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;code&gt;construction&lt;&#x2F;code&gt; or &lt;code&gt;diagram&lt;&#x2F;code&gt; DSL for describing how to construct a diagram that can then be reasoned about; building
up the types of propositions by a series of operations that guarantees we’re not assuming invalid constructions in
the type.&lt;&#x2F;li&gt;
&lt;li&gt;Getting &lt;code&gt;leanblueprint&lt;&#x2F;code&gt; ‘working’, which probably means replacing it. I have &lt;code&gt;scripts&#x2F;DumpDecls.lean&lt;&#x2F;code&gt; which outputs
some JSON, I don’t like how manual the maintenance of LBP is, so something automated might just obviate the need for
all the TeX stuff. Whither plantuml, graphviz, or otherwise.&lt;&#x2F;li&gt;
&lt;li&gt;Extending &lt;code&gt;Betweenness&lt;&#x2F;code&gt; to arbitrary length, inferring all the internal conditions; this notation would simplify the
density axiom a bit, and is pretty natural.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I think the plan is to prove the corollaries, merge, then figure out which way to extend; I definitely need to do some
more refactoring and cleaning, I think the blueprint stuff will help.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>4-MAR-2026</title>
        <published>2026-03-04T00:00:00+00:00</published>
        <updated>2026-03-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/4-mar-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/4-mar-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/4-mar-2026/">&lt;h2 id=&quot;0020&quot;&gt;0020&lt;&#x2F;h2&gt;
&lt;p&gt;Some thoughts before guitar and bed.&lt;&#x2F;p&gt;
&lt;p&gt;I think I need some work around &lt;code&gt;concurrence&lt;&#x2F;code&gt;s, which are groups of concurrent lines.&lt;&#x2F;p&gt;
&lt;p&gt;A frequent headache is managing various appelates of the same line. A set of collinear points induces &lt;code&gt;O(n^2)&lt;&#x2F;code&gt; ‘line
throughs’ by picking pairs of their points. All of these lines are geometrically identical; but in the prover, they’re a
big ol’ pain in the ass. I’ve been thinking about this in the context of more automation for distinct &#x2F; collinear, but
there are a couple properties of these things that are kind of interesting.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Any subset of a distinct&#x2F;collinear&#x2F;concurrent set is distinct&#x2F;collinear&#x2F;concurrent – follows from the underlying pairwise equality&#x2F;inequality&lt;&#x2F;li&gt;
&lt;li&gt;for a ‘negative’ property, like distinct, combining two distinct hypotheses is pretty difficult, it requires &lt;code&gt;M * N&lt;&#x2F;code&gt;
proofs, where &lt;code&gt;M&lt;&#x2F;code&gt; and &lt;code&gt;N&lt;&#x2F;code&gt; are the numbers of points in the structure.&lt;&#x2F;li&gt;
&lt;li&gt;for positive properties, it’s often possible to satisfy entry much more easily. Collinear points only need to prove
they lie on at two induced lines; Concurrent lines only need to prove they’re equal to any of the other lines in the
set.&lt;&#x2F;li&gt;
&lt;li&gt;Concurrency and collinearity are related – all those linethroughs are concurrent, and concurrent lines share the
same underlying collinear set.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It’s neat how being forced into hyperformality here makes it really clear to see some of the dualities – theorems have
very similar proofs despite the type change, and even the underlying plumbing is really just considering the
relationships between points and sets of points.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, the aim is to build some more structures, probably divide up the &lt;code&gt;theory&lt;&#x2F;code&gt; section more, I’m not super happy
with the way it’s broken by chapter, I think it’s maybe better to try to further divide up things; I believe there
should be a way to re-export from the various files; so that I don’t have to import everything by hand; but to be honest
the module system (or import system, not really sure which is which) is a mystery.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>3-MAR-2026</title>
        <published>2026-03-03T00:00:00+00:00</published>
        <updated>2026-03-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/3-mar-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/3-mar-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/3-mar-2026/">&lt;h2 id=&quot;2245&quot;&gt;2245&lt;&#x2F;h2&gt;
&lt;p&gt;Prop 3.3 is done, but nasty; it’s actually been done for a bit but I’ve been working on something else. A couple things,
actually.&lt;&#x2F;p&gt;
&lt;p&gt;First I got &lt;code&gt;separate&lt;&#x2F;code&gt; working so now &lt;code&gt;distinct&lt;&#x2F;code&gt; conditions are pretty easy to deal with. Ex 3.1 is much improved as a
result.&lt;&#x2F;p&gt;
&lt;p&gt;I started working on generating the blueprint; but there’s a ways to go.&lt;&#x2F;p&gt;
&lt;p&gt;The proof of 3.3 is very long, and I have to replicate it pretty heavily to prove the other half of the condition; which
is pretty gnar. It’s the same up to some renaming, but I am having trouble seeing what I could extract. I did do a bit
to allow &lt;code&gt;collinear&lt;&#x2F;code&gt; conditions to stand in directly for lines in all but the case where I’m trying to prove &lt;code&gt;A on cL&lt;&#x2F;code&gt;,
where &lt;code&gt;cL&lt;&#x2F;code&gt; is a collinear condition. The prover gets confused about what kind of membership it should use, which breaks
stuff.&lt;&#x2F;p&gt;
&lt;p&gt;I might try just winging it with the other half and see if I find a shorter approach, I have an advantage of not minding
tedious cases that maybe would scare off someone in a setting where case-reasoning is cheaper.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>On Proving with Lean</title>
        <published>2026-03-02T00:00:00+00:00</published>
        <updated>2026-03-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/letters/shae-erisson/2-mar-2026/"/>
        <id>https://disturbed-circles.com/letters/shae-erisson/2-mar-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/letters/shae-erisson/2-mar-2026/">&lt;p&gt;2-MAR-2026&lt;&#x2F;p&gt;
&lt;p&gt;Hey Shae,&lt;&#x2F;p&gt;
&lt;p&gt;We (very) briefly chatted on Mastodon about my excitement around Lean tactic metaprogramming, and you mentioned it would
make a good blogpost, and I wanted to agree; but I kind of hate blogging. I’ve been doing this “LOG.md” thing for a bit;
and I like that, but it doesn’t &lt;em&gt;feel&lt;&#x2F;em&gt; right for an explanatory blog. I use it more as a journal or engineering log or
scratchpad. I’ve been trying to embrace my hyperlexia, and this is a good way to do it, but it does feel a little weird
to write a blog-ish explainer&#x2F;experience report in it.&lt;&#x2F;p&gt;
&lt;p&gt;I guess it’s because I don’t like the sort of anonymous audience of a blogpost; I know someone &lt;em&gt;might&lt;&#x2F;em&gt; read it, but it
feels itchy to write something someone only &lt;em&gt;might&lt;&#x2F;em&gt; read. I spend a lot of time thinking about writing and writing about
thinking, and I &lt;em&gt;care&lt;&#x2F;em&gt; about it a lot. I think my identity is in it a bit, so it feels bad if I don’t know &lt;em&gt;someone&lt;&#x2F;em&gt;
will read it. With LOG.md, I know &lt;em&gt;I’ll&lt;&#x2F;em&gt; read it, so I don’t mind writing – a blogpost, though? All those hits could be
bots and crawlers, the comments just LLMs. It just feels lousy to not &lt;em&gt;know&lt;&#x2F;em&gt; someone has really read it. It feels like I
wasted my time.&lt;&#x2F;p&gt;
&lt;p&gt;But, as sometimes happens when my anxiety spikes about stuff, I had an idea. I may not be able to ensure that an
anonymous audience is nonempty, as a blogpost would require, but an open letter? I can guarantee at least &lt;em&gt;one&lt;&#x2F;em&gt; person
reads it, the recipient&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A long time ago in #haskell-cafe I posted my then-current phone number in hex because I, being a college freshman,
hadn’t yet learned that obfuscation is not the same as encryption. You called my cell. I answered and was confused. I
realized the lesson. I remember chatting a bunch in those salad days on IRC, and I have the sense that you would
appreciate this approach to ‘blogging’; I hope you don’t mind being my test subject.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, the meat of the letter, tactic programming in Lean4.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;geometry&quot;&gt;Geometry&lt;&#x2F;h1&gt;
&lt;p&gt;I’ve been working on this thing (&lt;code&gt;geometry_is_your_friend&lt;&#x2F;code&gt;) as a little project to learn Lean. It’s formalizing Martin
Greenberg’s &lt;em&gt;Euclidean and Noneuclidean Geometry&lt;&#x2F;em&gt;. In geometry, one frequently deals with small collections of objects
with simple (often pairwise) relations, &lt;code&gt;distinct&lt;&#x2F;code&gt; and &lt;code&gt;collinear&lt;&#x2F;code&gt; are the two big ones, and the former is especially
annoying when you have more than a few distinct points; The number of hypotheses in a list of distinct points is
&lt;code&gt;O(n^2)&lt;&#x2F;code&gt;, so it rapidly becomes very messy in a proof to bookkeep all those hypotheses, and proving a &lt;code&gt;distinct&lt;&#x2F;code&gt; goal is
a &lt;em&gt;real&lt;&#x2F;em&gt; bear. Lean offers good facilities for creating custom syntax, and so it was quite easy to create a custom proof
term:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;distinct A B C D ... := A ≠ B ∧ A ≠ C ∧ A ≠ D ∧ A ≠ ... ∧ B ≠ C ∧ B ≠ ... ∧ C ≠ ... ∧ ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which I can use like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; (A B C D : Point) (h : distinct A B C D) : A ≠ B ∧ B ≠ C ∧ A ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That example also shows the tactic counterpart, &lt;code&gt;distinguish&lt;&#x2F;code&gt;; which tries to automatically close goals based on the
&lt;code&gt;distinct&lt;&#x2F;code&gt; hypotheses it can find in the proofstate. The initial version was just the &lt;code&gt;distinct&lt;&#x2F;code&gt; term, and it barely
worked, resulting in a lot of proofs like this one:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;-- p146. Given A-B-C and A-C-D:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;  (a) Prove that A,B,C, and D are four distinct points (the proof requires an axiom)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;-&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;theorem&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Ex1.a&lt;&#x2F;span&gt;&lt;span&gt; : A - B - C ∧ A - C - D -&amp;gt; distinct A B C D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro ⟨ABC, ACD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; distinctABC := Betweenness.abc_imp_distinct ABC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; distinctACD := Betweenness.abc_imp_distinct ACD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  simp only [ne_eq, List.pairwise_cons, List.mem_cons, List.not_mem_nil, or_false, forall_eq_or_imp,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    forall_eq, IsEmpty.forall_iff, implies_true, List.Pairwise.nil, and_self, and_true]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; AneB : A ≠ B := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctABC A B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; AneC : A ≠ C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctABC A C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; BneC : B ≠ C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctABC B C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; AneD : A ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctACD A D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; CneD : C ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctACD C D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  refine ⟨⟨AneB, AneC, AneD⟩, ⟨BneC, ?_⟩, CneD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; BneD : B ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctACD B D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  by_contra! BeqD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  rw [&amp;lt;- BeqD] at ACD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exact Betweenness.absurdity_abc_acb ⟨ABC, ACD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This uses an earlier version of &lt;code&gt;distinguish&lt;&#x2F;code&gt; which just automates a single proof of a single inequality fact; and that
only after&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;simp only [ne_eq, List.pairwise_cons, List.mem_cons, List.not_mem_nil, or_false, forall_eq_or_imp,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;forall_eq, IsEmpty.forall_iff, implies_true, List.Pairwise.nil, and_self, and_true]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;has cluttered my proof. This is ugly, and so I dug into the guts of the tactic mode to figure it out. Eventually, after
a whole bunch of cajoling, and while only truly understanding like, 20% of it; but it works. I went through the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mirefek&#x2F;lean-tactic-programming-guide&#x2F;tree&#x2F;main&quot;&gt;&lt;em&gt;Lean
Tactic Programming Guide&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; and cannot speak highly
enough of it as a significantly better introduction to the topic then this will be. The Lean tactic system is &lt;em&gt;really&lt;&#x2F;em&gt;
neat; and also a &lt;em&gt;headtrip&lt;&#x2F;em&gt; to understand. It’s very easy to confuse yourself in terms of what level you’re thinking at;
and I spent a fair few hours confused because I hadn’t realized I needed to convert from the &lt;code&gt;LocalDecl&lt;&#x2F;code&gt; to an actual
&lt;code&gt;Expr&lt;&#x2F;code&gt; in order to reference a hypothesis inside the inequality proof.&lt;&#x2F;p&gt;
&lt;p&gt;Actually, let me back up a little and talk about the Proof environment and the proofstate. This is based on having read
through the &lt;em&gt;Lean Tactic Programming Guide&lt;&#x2F;em&gt; over the course of an evening. It is with that hubris the rest of this
letter is written.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;proofstate&quot;&gt;Proofstate&lt;&#x2F;h1&gt;
&lt;p&gt;A proof, as you know, is a program; and in particular it is a program of both values and types. Values have Types, and
Types, in Lean, can depend on Values. The nice thing about Lean’s syntax is that it makes heavy use of unicode, so you
can encode a statement using relatively natural mathematical syntax without having to resort to LaTeX. Lean uses some
clever editor features and a bit of muscle memory which develops pretty quickly. So something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : distinct A B C D E -&amp;gt; A ≠ X -&amp;gt; A ≠ B ∧ (B ≠ C ∧ X ≠ A) ∧ (∀ P : Nat, P = &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt; P &amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) ∧ (C ≠ D ∨ V = W) := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;gets entered like&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : distinct A B C D E -&amp;gt; A \ne X -&amp;gt; A \ne B \and (B \ne C \and X \ne A) \and (\&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;forall&lt;&#x2F;span&gt;&lt;span&gt; P : Nat, P = &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt; P &amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) \and (C \ne D \or V = W) := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and your preferred editor will do the right thing, assuming your plugins are in order.&lt;&#x2F;p&gt;
&lt;p&gt;This statement gets translated to a ‘proofstate’ like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A B C D E X : α✝¹&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;V W : α✝&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;h : Distinct [A, B, C, D, E]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AneX : A ≠ X&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;⊢ A ≠ B ∧ (B ≠ C ∧ X ≠ A) ∧ (∀ (P : ℕ), P = &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; → P &amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) ∧ (C ≠ D ∨ V = W)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is split into two parts, the &lt;code&gt;Context&lt;&#x2F;code&gt;, which contains all the facts you know, and the &lt;code&gt;Goal&lt;&#x2F;code&gt;, which comes after
the &lt;code&gt;⊢&lt;&#x2F;code&gt; and is the term you have to construct out of your pieces, you can have multiple simultaneous goals; which just
means you have multiple branches of a conjunction to prove. All this is the ‘proofstate’ of your theorem. When proving,
you can either directly construct terms using the underlying dependently typed functional language, like in this part of
a proof of prop 2.2:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- This &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;lemma&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; was not suggested by the author, but is handy. The proof is not long and simply establishes the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Parallel&amp;#39; fact for each pair of lines. We need the unique point and the negative condition to build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;these&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;have hABnotparBC&lt;&#x2F;span&gt;&lt;span&gt; : (AB ∦ BC) := Line.intersecting_lines_are_not_parallel hPonAB hPonBC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; hABnotparAC : (AB ∦ AC) := Line.intersecting_lines_are_not_parallel hPonAB hPonAC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; hBCnotparAC : (BC ∦ AC) := Line.intersecting_lines_are_not_parallel hPonBC hPonAC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where I construct a proof that a bunch of lines are not parallel to one another by directly invoking the function
provided by the &lt;code&gt;Line.intersecting_lines_are_not_parallel&lt;&#x2F;code&gt; lemma. This is very similar to plain old functional
programming. &lt;code&gt;Line.intersecting_lines_are_not_parallel&lt;&#x2F;code&gt; is a ‘lemma’, sure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;lemma&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; intersecting_lines_are_not_parallel&lt;&#x2F;span&gt;&lt;span&gt; {L M : Line} {P : Point} : (P on L) -&amp;gt; (P on M) -&amp;gt; (L ∦ M)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;… in the sense that it is a logical statement about lines, but it’s also a function that takes two facts (and some
implicit variables those facts operate on) to produce a new fact.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;lemma&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; intersecting_lines_are_not_parallel&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Implicit arguments to the function are searched for in context when the function is called&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {L M : Line} {P : Point} :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -- input arguments, these &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; _type_ `P on L`, which is itself of type `&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (P on L) -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (P on M) -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -- output, a fact of type `(L ∦ M)`, which also has type `&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (L ∦ M)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this mode, “term mode”, we act much more like a Haskell-adjacent language. It’s quite similar to the old pointfree
golf I assume people still play with Haskell.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: You can also see some custom syntax there for ‘not parallel’, this is very simple to achieve using the simplest
notation-related tool in Lean, &lt;code&gt;notation&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;notation&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt; L &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot; ∥ &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; M =&amp;gt; Parallel L M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;notation&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt; L &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot; ∦ &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; M =&amp;gt; ¬(Parallel L M)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The syntax side of things is a &lt;em&gt;deep&lt;&#x2F;em&gt; well, I’ll talk about it a little more at the end, but it suffices to say that I
have not yet found too many areas where I think the syntax couldn’t be bent to whatever will pulls on it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;You can also use &lt;code&gt;tactic&lt;&#x2F;code&gt; mode to prove theorems, and this is what I wanted to do for the &lt;code&gt;distinct&lt;&#x2F;code&gt; term. Tactics are
small programs that run against the ‘proofstate’, they can inspect known facts, manipulate the goal, and create new
goals by ‘proving’ old goals. Those proofs themselves can have interior goals, which allows a tactic to incrementally
break down a big type into a series of smaller types. Equivalently, it separates a complicated logical statement into
many simpler ones.&lt;&#x2F;p&gt;
&lt;p&gt;In Haskell, type-directed programming is this sort of delightful flow state where you gain the ‘if it compiles, it
probably works’ feeling that is occasional but fleeting in Haskell, and rarely even felt outside of languages not in its
lineage. Lean is quite good at eliciting that feeling, and this makes sense because the type system is powerful enough
to accurately represent mathematics directly, and mathematics is only ever that feeling (for me, at least).&lt;&#x2F;p&gt;
&lt;p&gt;Tactics are quite powerful, but they’re also a little magical. A tactic like &lt;code&gt;tauto&lt;&#x2F;code&gt; or &lt;code&gt;simp&lt;&#x2F;code&gt; or &lt;code&gt;aesop&lt;&#x2F;code&gt; might prove
your goal, but the reasoning might be opaque, or the proof it generates highly complicated; so it’s worthwhile, IMO, to
learn how to build up from terms, as it’s usually a lot more parsimonious. Once you get the hang, it’s a lot easier to
think about it in terms of simple function applications. When building tactics, term-mode proving is handy for
constructing proofs without having to drop into the &lt;code&gt;evalTactic&lt;&#x2F;code&gt; mode. Once you start invoking nested tactics you are,
at least in spirit, ceding some control over what the prover is doing (which I’ll show later when we get to the meat of
the &lt;code&gt;distinguish&lt;&#x2F;code&gt; and &lt;code&gt;separate&lt;&#x2F;code&gt; tactics).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-distinct-should-do&quot;&gt;What distinct should do&lt;&#x2F;h1&gt;
&lt;p&gt;In particular, I need three things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;notation for small collections of pairwise distinct values of some type; I suspect it’ll almost always be points, but
it could be useful for lines at some point too.&lt;&#x2F;li&gt;
&lt;li&gt;a way to automatically prove inequality goals using available hypotheses in the context&lt;&#x2F;li&gt;
&lt;li&gt;a way to destructure a distinct goal into a right-associated (“flat”) conjunction of inequality goals&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This would allow me to work with the &lt;code&gt;distinct&lt;&#x2F;code&gt; condition as a goal, known fact, and tool to prove these simple cases
automatically by automatically looking at the lists of known-distinct items and trying to prove the goal without
cluttering the proofstate (which is important for performance reasons).&lt;&#x2F;p&gt;
&lt;p&gt;So far I’ve found that there are really only three ‘kinds’ of things you can do in Lean while proving; you can
manipulate and add facts to the context, you can manipulate and split or glue goals together, or you can close goals.
Tactics, my intuition says, should have an answer for how they work in each of those states. In my case, &lt;code&gt;distinct&lt;&#x2F;code&gt; is a
type that can be used to express pairwise distinct relationships between (relatively) small, finite lists of variables;
&lt;code&gt;distinguish&lt;&#x2F;code&gt; is a tactic that can prove inequalities using &lt;code&gt;distinct&lt;&#x2F;code&gt; hypotheses, and &lt;code&gt;separate&lt;&#x2F;code&gt; is a tactic that
deconstructs a &lt;code&gt;distinct&lt;&#x2F;code&gt; term into an equivalent set of inequalities. This covers the three cases.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;how-it-works&quot;&gt;How it works&lt;&#x2F;h1&gt;
&lt;p&gt;Here’s the lede I’ve kept buried: &lt;strong&gt;the proofstate is just a Monad&lt;&#x2F;strong&gt;. Essentially, it’s a little virtual machine that
tracks the hypotheses in the &lt;code&gt;LocalContext&lt;&#x2F;code&gt; as a bunch of &lt;code&gt;LocalDecls&lt;&#x2F;code&gt;. These can be easily turned into &lt;code&gt;Expr&lt;&#x2F;code&gt;s, which
is the type of Lean Statements in the AST after elaboration; the Lean parser is a multilayer system, and &lt;code&gt;Expr&lt;&#x2F;code&gt; is the
last step before running actual code&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. This machine is exposed via the &lt;code&gt;TacticM&lt;&#x2F;code&gt; monad, which is essentially a DSL
for manipulating proofstates. Proofstates themselves are just a collection of variables that get wired together; they
come in three flavors of interest:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;FVars
&lt;ul&gt;
&lt;li&gt;Free variables, these are the &lt;code&gt;A B C D E X V W&lt;&#x2F;code&gt; above, but also &lt;code&gt;h&lt;&#x2F;code&gt; is an FVar.&lt;&#x2F;li&gt;
&lt;li&gt;I prefer to think of it as ‘FactVariable’, which I think is mostly okay.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;BVars
&lt;ul&gt;
&lt;li&gt;Bound variables, these are the arguments to functions.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;P&lt;&#x2F;code&gt; in the &lt;code&gt;(∀ (P : ℕ), P = 3 → P &amp;gt; 1)&lt;&#x2F;code&gt; above is a BVar&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;MVars
&lt;ul&gt;
&lt;li&gt;Meta variables, or holes, these are associated with the current goal(s).&lt;&#x2F;li&gt;
&lt;li&gt;Each must get assigned a term of a matching type to be closed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;code&gt;TacticM&lt;&#x2F;code&gt; monad exposes a simple programming language to interact with these variables, and the &lt;code&gt;Qq&lt;&#x2F;code&gt; library and
&lt;code&gt;Lean&lt;&#x2F;code&gt; namespace provide the API to manipulate it. I started&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; with the following to cover #1 above:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;structure&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Distinct&lt;&#x2F;span&gt;&lt;span&gt; {α : &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Type&lt;&#x2F;span&gt;&lt;span&gt;*} (points : List α) : &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  pairwise : List.Pairwise (· ≠ ·) points&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;namespace&lt;&#x2F;span&gt;&lt;span&gt; Distinct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- ... snip ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- Custom &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax for&lt;&#x2F;span&gt;&lt;span&gt; distinct&#x2F;distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;declare_syntax_cat&lt;&#x2F;span&gt;&lt;span&gt; distinct_binder&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax&lt;&#x2F;span&gt;&lt;span&gt; ident+ &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot; : &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; term : distinct_binder&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;distinct&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ident+ : term&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;macro_rules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | `(distinct $xs*) =&amp;gt; `(Distinct [$xs,*])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- ... snip ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;span&gt; Distinct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gets me to &lt;code&gt;distinct A B C D E&lt;&#x2F;code&gt; as a proof term, I can also write &lt;code&gt;Distinct [A,B,C,D,E]&lt;&#x2F;code&gt; but that’s much more
cumbersome. The syntax category is probably not necessary, but it feels nice to give everything its own little home.
Next I added a couple example statements to test with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : distinct A B C D E -&amp;gt; A ≠ X -&amp;gt; A ≠ B ∧ B ≠ C ∧ X ≠ A ∧ (∀ P : Nat, P = &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt; P &amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) ∧ C ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro h AneX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -- this part doesn&amp;#39;t matter, the extra assertions are just to make sure the distinguish step doesn&amp;#39;t oversolve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exact AneX.symm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro P Peq2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  rw [Peq2]; trivial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : distinct A B C D E -&amp;gt; A ≠ X -&amp;gt; A ≠ B ∧ (B ≠ C ∧ X ≠ A) ∧ (∀ P : Nat, P = &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; -&amp;gt; P &amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) ∧ (C ≠ D ∨ V = W) := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro h AneX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  · exact AneX.symm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  · intro P Peq3; rw [Peq3]; trivial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  · &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; CneD : C ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    left; trivial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; (A B C D : Point) (h : distinct A B C D) : A ≠ B ∧ B ≠ C ∧ A ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; (h : distinct A B) : A ≠ B := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This shows how &lt;code&gt;distinguish&lt;&#x2F;code&gt; should work; in particular it should:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Flatten and split the goal tree so that every part of the conjunction is its own goal.&lt;&#x2F;li&gt;
&lt;li&gt;Make a list of all the goals that are just an inequality statement&lt;&#x2F;li&gt;
&lt;li&gt;Find all the hypotheses that are created by &lt;code&gt;distinct&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Use the hypotheses from #3 to try to prove every marked goal from #2&lt;&#x2F;li&gt;
&lt;li&gt;Leave the rest&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It is certainly possible to do this in other ways, or to extend the traversal through disjunctions or quantifiers, but
the 80% case is ‘flatten things and prove a bunch of single inequalities’ so I started there. The first step is
splitting the goals, this went through a couple iterations, but landed at:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;-- Split conjunction goal into MVars and track which are inequalities -&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;partial&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; splitAndTagGoals&lt;&#x2F;span&gt;&lt;span&gt; : TacticM (List MVarId × List Nat) := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span&gt; goal ← getMainGoal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  let rec&lt;&#x2F;span&gt;&lt;span&gt; splitAndExtract (g : MVarId) (idx : Nat) : TacticM (List MVarId × List (Nat × Bool)) := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← g.getType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    have&lt;&#x2F;span&gt;&lt;span&gt; goalTypeProp : Q(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span&gt;) := goalType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    match&lt;&#x2F;span&gt;&lt;span&gt; goalTypeProp &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | ~q($a ∧ $b) =&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -- Split conjunction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      setGoals [g]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      evalTactic (← `(tactic| constructor))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span&gt; [leftGoal, rightGoal] ← getGoals | &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;Expected two goals after constructor&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -- Recursively process both sides&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span&gt; (leftMvars, leftTags) ← splitAndExtract leftGoal idx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span&gt; rightIdx := idx + leftMvars.length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span&gt; (rightMvars, rightTags) ← splitAndExtract rightGoal rightIdx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span&gt; (leftMvars ++ rightMvars, leftTags ++ rightTags)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | ~q(@Ne _ $a $b) =&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -- Inequality - mark as such&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span&gt; ([g], [(idx, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;)])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | _ =&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -- Other goal - not an inequality&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span&gt; ([g], [(idx, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;)])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span&gt; (mvars, tags) ← splitAndExtract goal &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span&gt; ineqIndices := tags.filterMap (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;fun&lt;&#x2F;span&gt;&lt;span&gt; (idx, isIneq) =&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; isIneq &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt; some idx &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt; none)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; (mvars, ineqIndices)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The majority of tactic writing, it seems, is bookkeeping. There is a great deal of bookkeeping in this, but it’s a
pretty simple idea – grab the goal (&lt;code&gt;getMainGoal&lt;&#x2F;code&gt;), then try to break it into its components using the
&lt;code&gt;splitAndExtract&lt;&#x2F;code&gt; helper defined inline; it does this by simple pattern matching on the goal – if it’s a conjunction
(&lt;code&gt;q($a ∧ $b)&lt;&#x2F;code&gt;, which is a quotation of the literal &lt;code&gt;A ∧ B&lt;&#x2F;code&gt; with match placeholder for the left and right sides of the
conjunction), then recurse down each side, updating the index of the goal, if it’s an inequality (&lt;code&gt;~q(@Ne _ $a $b)&lt;&#x2F;code&gt;),
mark it as such, and otherwise mark it as a non-equality.&lt;&#x2F;p&gt;
&lt;p&gt;The other part of this function generates (via the &lt;code&gt;constructor&lt;&#x2F;code&gt; tactic in the first branch of the match) an &lt;code&gt;MVar&lt;&#x2F;code&gt; for
each new goal; so the result is a list of &lt;code&gt;MVarId&lt;&#x2F;code&gt;s, one for each goal; and a second list which indexes the first to
tell us where all the inequality goals are (&lt;code&gt;ineqIndices&lt;&#x2F;code&gt;). This could maybe be done via pattern matching, but
&lt;code&gt;constructor&lt;&#x2F;code&gt; is a nice, predictable tactic, and shouldn’t cause trouble.&lt;&#x2F;p&gt;
&lt;p&gt;Now we’ve successfully decomposed the goal from a single conjunction tree (that is, it’s in some freely associated form,
not uniformly right-associated) to a ‘flat’ (right-associated) list of goals and an index of where the ones we can
prove with distinct are.&lt;&#x2F;p&gt;
&lt;p&gt;One bit that took me a little while to wrap my head around. When you get the goal it is an &lt;code&gt;MVarId&lt;&#x2F;code&gt;, but we need to
deal with its type as a syntactic element that represents a fixed proposition. A goal, ultimately, is just a slot that
expects a construction assigned to it of the appropriate type. It doesn’t carry any information directly with it, so in
order to talk about its type we have to look it up with &lt;code&gt;goal.getType&lt;&#x2F;code&gt;. This gives us an &lt;code&gt;Expr&lt;&#x2F;code&gt;, which seems like what
we need, because &lt;code&gt;Expr&lt;&#x2F;code&gt; is the representation of the syntax, but in fact we need to go one step further and work with
the &lt;code&gt;Q&lt;&#x2F;code&gt;-quoted version of this &lt;code&gt;Expr&lt;&#x2F;code&gt;, which allows us to pick it apart without worrying about the constraints of the
&lt;code&gt;Expr&lt;&#x2F;code&gt; type.&lt;&#x2F;p&gt;
&lt;p&gt;From the LTPG:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;– The data structure that is used to represent Lean expressions is &lt;code&gt;Lean.Expr&lt;&#x2F;code&gt;.
– Due to the nature of dependent type theory, &lt;code&gt;Lean.Expr&lt;&#x2F;code&gt; is used to encode types, terms and proofs.
– Thus, &lt;code&gt;Lean.Expr&lt;&#x2F;code&gt; is also what is checked by the Lean kernel when checking proofs.
– ctrl-click on &lt;code&gt;Lean.Expr&lt;&#x2F;code&gt; below to see its definition in the library.
#check Lean.Expr&lt;&#x2F;p&gt;
&lt;p&gt;– Lean has a handy library &lt;code&gt;Qq&lt;&#x2F;code&gt; to help you build &lt;code&gt;Lean.Expr&lt;&#x2F;code&gt; terms with a convenient notation.
open Qq&lt;&#x2F;p&gt;
&lt;p&gt;– &lt;code&gt;Q(...)&lt;&#x2F;code&gt; is a type annotation of an expression, and
– &lt;code&gt;q(...)&lt;&#x2F;code&gt; is an expression&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This took me a bit to grok, and I’m not sure it feels natural yet, but then again quotes and quasiquotes don’t seem like
the sort of thing you’re ever supposed to feel comfortable with, so I suppose it’s feeling the way it’s supposed to. The
type of &lt;code&gt;goalTypeProp&lt;&#x2F;code&gt; in:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← g.getType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; goalTypeProp : Q(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span&gt;) := goalType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;is the &lt;em&gt;quotation&lt;&#x2F;em&gt; of an arbitrary proposition, not a proposition itself. It’s a syntactic version of, e.g., &lt;code&gt;A ≠ B&lt;&#x2F;code&gt;,
not the statement &lt;code&gt;A ≠ B&lt;&#x2F;code&gt; itself. The same as the difference between: &lt;code&gt;&quot;A ≠ B&quot;&lt;&#x2F;code&gt; and &lt;code&gt;A ≠ B&lt;&#x2F;code&gt;. 🤯 I suppose there is a
reason they call it quoting.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing this function doesn’t do is try to disambiguate situations which are not simple conjunctions; consider a
proposition like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;distinct A B C D -&amp;gt; A ≠ B ∧ (C ≠ D ∨ V = W)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, it is easy to resolve: we know &lt;code&gt;A ≠ B := by distinguish&lt;&#x2F;code&gt; and &lt;code&gt;C ≠ D := by distinguish&lt;&#x2F;code&gt;, but the
&lt;code&gt;splitAndTagGoals&lt;&#x2F;code&gt; above will treat the &lt;code&gt;(C ≠ D ∨ V = W)&lt;&#x2F;code&gt; disjunction as unassailable. Similarly a condition like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;distinct A B -&amp;gt; ∀ P : &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span&gt;, A ≠ B ∨ P&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;is obviously true regardless of the choice of &lt;code&gt;P&lt;&#x2F;code&gt;, but the current tool won’t look inside the quantifier to reduce that
to a proof of &lt;code&gt;∀ P : Prop, True&lt;&#x2F;code&gt;, even though one could conclude &lt;code&gt;A ≠ B&lt;&#x2F;code&gt; easily.&lt;&#x2F;p&gt;
&lt;p&gt;Limitations noted, now I have the broken up goal. Next, I need to gather up the tools I’ll need; I don’t want to try to
use every available fact-in-evidence, just the &lt;code&gt;distinct&lt;&#x2F;code&gt; properties that I know about; this is not the &lt;em&gt;best&lt;&#x2F;em&gt; way to do
things, as there might be ambient facts that could be used to prove the property, but hunting for them involves doing a
lot more mangling of the proofstate, and things were already complicated enough. Here’s the function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;-- Finds all `Distinct` hypotheses in the local context -&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; findDistinctHypos&lt;&#x2F;span&gt;&lt;span&gt; : TacticM (List LocalDecl) := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span&gt; lctx ← getLCtx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  let mut&lt;&#x2F;span&gt;&lt;span&gt; distinctHypos : List LocalDecl := []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span&gt; decl &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; lctx &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; decl.isImplementationDetail &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; declType ← instantiateMVars decl.type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; declType.isAppOfArity ``Distinct &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      distinctHypos := decl :: distinctHypos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; distinctHypos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This produces a list of &lt;code&gt;LocalDecl&lt;&#x2F;code&gt;s that match the signature of the distinct structure. The &lt;code&gt;declType.isAppofArity&lt;&#x2F;code&gt;
line is what does that, it’s looking for a literal &lt;code&gt;Distinct&lt;&#x2F;code&gt; of arity 2; which I don’t think is the &lt;em&gt;best&lt;&#x2F;em&gt; way to find
these things, but it is &lt;em&gt;a&lt;&#x2F;em&gt; way and the first one that worked; I suspect there are better tools for this (probably
pattern matching on the type), but for a simple structure like &lt;code&gt;Distinct&lt;&#x2F;code&gt;, it’s easy enough to just search for it. It’s
of arity 2 because it has two parameters, the list of points (its second parameter) is an explicit parameter, but the
type of the values in that list is not constrained to &lt;em&gt;only&lt;&#x2F;em&gt; points, and so there is an implicit type parameter.&lt;&#x2F;p&gt;
&lt;p&gt;Lean is pretty aggressive about making parts of the language implicit, which is a big step in making the language more
ergonomic than other languages I’ve tried. Ergonomics rarely are the only reason I stop using a prover, but it’s
frequently the thing that makes it impossible to get over whatever other struggles I have. Lean does a very good job
here of making it possible – even easy – to let context fill in details you don’t want to care about but need to care
about, probably my favorite part of the language.&lt;&#x2F;p&gt;
&lt;p&gt;The code itself is simple; it walks over each fact in the &lt;code&gt;LocalContext&lt;&#x2F;code&gt; and builds up a list; the &lt;code&gt;let mut&lt;&#x2F;code&gt; is a little
bit of a lie, as I understand. It hides a &lt;code&gt;State&lt;&#x2F;code&gt;-monad-adjacent thing that lets you pretend the variable is mutable
even in this pure-ish environment. This makes it pretty pleasant to write these little programs that query the
proof-state; it’s not too far away from a regular imperative language about as wieldy as shell; not powerful, but
powerful enough.&lt;&#x2F;p&gt;
&lt;p&gt;Once it finds a declaration of the correct type, it adds it to a list of hypotheses that we use in the following
monster&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;#fn-4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; runDistinct&lt;&#x2F;span&gt;&lt;span&gt; : TacticM Unit := withMainContext &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; (allGoals, ineqIndices) ← splitAndTagGoals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; distinctHypos ← findDistinctHypos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; solvedIndices : List Nat := []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; idx &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; ineqIndices &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span&gt; goalMVar := allGoals[idx]!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      setGoals [goalMVar]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      for&lt;&#x2F;span&gt;&lt;span&gt; hypo &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; distinctHypos &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;. &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt; into the fvars on either side&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← goalMVar.getType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        have&lt;&#x2F;span&gt;&lt;span&gt; goalTypeProp : Q(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Prop&lt;&#x2F;span&gt;&lt;span&gt;) := goalType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if let&lt;&#x2F;span&gt;&lt;span&gt; ~q(@Ne $typ $lhs $rhs) := goalTypeProp &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -- 2a. &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; the fvars are the same, &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt; the two things are equal, reject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          if&lt;&#x2F;span&gt;&lt;span&gt; lhs.fvarId! != rhs.fvarId! &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;. now search the `points` of the `distinct` condition and we can conclude inequality based&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            -- on the pairwise relationship&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            if let&lt;&#x2F;span&gt;&lt;span&gt; some points ← Distinct.getPointsExpr hypo.toExpr &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              -- establish that both lhs and rhs are &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; the list of distinct variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;              let&lt;&#x2F;span&gt;&lt;span&gt; lhsIn := points.any (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;fun&lt;&#x2F;span&gt;&lt;span&gt; p =&amp;gt; p.isFVar &amp;amp;&amp;amp; p.fvarId! == lhs.fvarId!)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;              let&lt;&#x2F;span&gt;&lt;span&gt; rhsIn := points.any (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;fun&lt;&#x2F;span&gt;&lt;span&gt; p =&amp;gt; p.isFVar &amp;amp;&amp;amp; p.fvarId! == rhs.fvarId!)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;              if&lt;&#x2F;span&gt;&lt;span&gt; lhsIn &amp;amp;&amp;amp; rhsIn &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                -- we can prove it, we &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; the technology&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                let&lt;&#x2F;span&gt;&lt;span&gt; proofGoal ← mkFreshExprMVar goalType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                let&lt;&#x2F;span&gt;&lt;span&gt; proofMVar := proofGoal.mvarId!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                setGoals [proofMVar]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                let&lt;&#x2F;span&gt;&lt;span&gt; hypoName := mkIdent hypo.userName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                -- prove &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;using&lt;&#x2F;span&gt;&lt;span&gt; aesop + simp, this is not ideal, it should be possible to construct a direct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                -- proof, but it&amp;#39;s not low-effort, so FIXME some other time.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                evalTactic (← `(tactic| (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                  have&lt;&#x2F;span&gt;&lt;span&gt; h := ($hypoName).pairwise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  simp only [List.Pairwise, List.mem_cons] at h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  aesop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                )))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                -- Check &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; it was solved, &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt; assign the goal &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; it is.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                if&lt;&#x2F;span&gt;&lt;span&gt; ← proofMVar.isAssigned &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                  let&lt;&#x2F;span&gt;&lt;span&gt; proof ← instantiateMVars proofGoal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  goalMVar.assign proof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; this case, lhs is _literally the same &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;variable&lt;&#x2F;span&gt;&lt;span&gt; reference_ as rhs, so we are trying to prove&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            -- ¬(rfl A), which is just &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;, so the whole conjunction is &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt; and we should replace the goal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;with&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;. I&amp;#39;m not doing that now, but it&amp;#39;s doable, I think.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;lhs is identical to rhs, you&amp;#39;re trying to prove A ≠ A, and that&amp;#39;s no bueno&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          logInfo &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;m!&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;goalType&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -- 2b. &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;span&gt; nothing, this case is not possible because we&amp;#39;re only inspecting inequalities.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;not possible&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -- bookkeeping to make sure we set the goals correctly later.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -- FIXME: I think this could probably be based on whether or not the mvar is assigned?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span&gt; ← goalMVar.isAssigned &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        solvedIndices := idx :: solvedIndices&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -- Collect unsolved goals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; unsolvedGoals : List MVarId := []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; [:allGoals.length] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span&gt; !solvedIndices.contains i &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        unsolvedGoals := unsolvedGoals ++ [allGoals[i]!]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    setGoals unsolvedGoals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This integrates everything together along with a couple other helpers; but the strategy is really simple and mostly
contained in the &lt;code&gt;-- 2a&lt;&#x2F;code&gt; branch, and within that, the main branch is the one that actually does the work. After the
initial preamble which splits the goal, gathers the facts, and allocates a list for all the goals we automatically
solve; I iterate over each inequality and try to close it with one of the available &lt;code&gt;distinct&lt;&#x2F;code&gt; hypotheses I gathered. I
do this by first checking that the two sides are not ‘literally’ the same, that is, they are different &lt;code&gt;fVars&lt;&#x2F;code&gt;. Recall
that an &lt;code&gt;fVar&lt;&#x2F;code&gt; represents a ‘fact’ variable, and in my case they’ll usually represent named points, so right now I want
to fail if any of the facts we’re trying to prove is a simple falsehood of &lt;code&gt;A ≠ A&lt;&#x2F;code&gt;, as something like &lt;code&gt;simp&lt;&#x2F;code&gt; will
already cover that case. Once we’re in the branch, the process is simple – if the respective &lt;code&gt;fVars&lt;&#x2F;code&gt; for the left and
right sides of the inequality are present in the same list of distinct variables, we know there is a proof they are not
equal, so I construct it using &lt;code&gt;simp&lt;&#x2F;code&gt; and &lt;code&gt;aesop&lt;&#x2F;code&gt;; two existing automated tactics that can resolve most simply proofs.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;simp&lt;&#x2F;code&gt; reduces the &lt;code&gt;distinct&lt;&#x2F;code&gt; goal to the relevant inequalities, and &lt;code&gt;aesop&lt;&#x2F;code&gt; is able to use that to close. I could,
and probably should, directly construct the proof here; but doing so is a little messy and this works alright for most
cases. Since the number of variables is relatively small, it’s unlikely this will become a huge performance issue except
in extreme cases. The reason to be wary here is &lt;code&gt;aesop&lt;&#x2F;code&gt; and &lt;code&gt;simp&lt;&#x2F;code&gt; both iterate over available theorems in the
environment, &lt;em&gt;not&lt;&#x2F;em&gt; just the hypotheses in your proofstate. Tagging a theorem with &lt;code&gt;@[simp]&lt;&#x2F;code&gt;, or equivalently with one of
the tags &lt;code&gt;aesop&lt;&#x2F;code&gt; cares about, will cause each of these tactics to consider them when running, which it then considers
recursively up to some user-defined limit. This can lead to two &lt;code&gt;spooky-action-at-a-distance&lt;&#x2F;code&gt; problems, like:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;adding a new &lt;code&gt;simp&lt;&#x2F;code&gt; tag or &lt;code&gt;aesop&lt;&#x2F;code&gt; tag can result in working proofs failing as they overflow the recursion stack&lt;&#x2F;li&gt;
&lt;li&gt;adding a new &lt;code&gt;simp&lt;&#x2F;code&gt; or &lt;code&gt;aesop&lt;&#x2F;code&gt; can also result in a performance problem on random theorems. If the new entry adds a
new path that can be recursed through, it may result in the prover spending time chasing rabbits.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The moral of the story is to be judicious about the use of &lt;code&gt;simp&lt;&#x2F;code&gt; and &lt;code&gt;aesop&lt;&#x2F;code&gt; both as tags and tactics. In this case,
the scope of available and relevant theorems is &lt;em&gt;relatively&lt;&#x2F;em&gt; small, and it should be okay. In principle there should be
a finitely constructible proof for these facts, and as the &lt;code&gt;FIXME&lt;&#x2F;code&gt; mentions, I should probably use it; but this is
certified Good Enough(tm).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Aside: It’s &lt;em&gt;really&lt;&#x2F;em&gt; interesting how performance of the prover becomes a concern for the math side of things. Earlier,
while working more directly on the geometry, I was pretty liberal using the &lt;code&gt;tauto&lt;&#x2F;code&gt; tactic; which more or less
brute-forces its way through a proof by trying to apply &lt;code&gt;simp&lt;&#x2F;code&gt;, &lt;code&gt;contradiction&lt;&#x2F;code&gt;, and any available hypothesis to the
goal to try to resolve it. In small contexts with few active hypotheses, it’s quick enough; but on one proof where I
had two dozen or so active facts, it ground the machine to a halt and my file would take tens of seconds to evaluate.
Real nasty.&lt;&#x2F;p&gt;
&lt;p&gt;The cool thing, though, is that good &lt;em&gt;programming&lt;&#x2F;em&gt; practices seem to translate naturally to good &lt;em&gt;mathematical&lt;&#x2F;em&gt;
practices. Spending time refactoring really does translate to better quality arguments that feel more elegant. I’ve
long associated refactoring with the feeling of a good proof technique or clever mathematical argument, it’s very
validating to see it play out in code.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Once I’ve attempted the proof, I check to see if I actually managed to assign the variable (it always should, another
benefit to a direct construction would be eliminating this branch), and then assign the goal to the MVar associated with
the proof; closing the goal.&lt;&#x2F;p&gt;
&lt;p&gt;The rest is bookkeeping, which Lean doesn’t do on its own. The actual tactic is very simple, but updating
the state is tricky.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;syntax-and-tooling&quot;&gt;Syntax and tooling&lt;&#x2F;h1&gt;
&lt;p&gt;All of this gets us through the &lt;em&gt;code&lt;&#x2F;em&gt; part of this, but there is a whole second step. At the beginning, I showed a bit
of the &lt;code&gt;notation&lt;&#x2F;code&gt; created for &lt;code&gt;distinct&lt;&#x2F;code&gt;, in fact, there are three items of syntax I need; I have the tools, but they
are not yet integrated, I could run a proof like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; (A B C D : Point) (h : distinct A B C D) : A ≠ B ∧ B ≠ C ∧ A ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  run_tac runDistinct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;but this is ugly, I prefer the &lt;code&gt;distinguish&lt;&#x2F;code&gt; keyword I set before. In fact, I need to be able to use this syntax in
three contexts as prior mentioned:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;As a hypothesis in a theorem statement, e.g. &lt;code&gt;distinct A B C -&amp;gt; ...&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;As a conclusion of a theorem statement, e.g., &lt;code&gt;... -&amp;gt; distinct A B C := by ...&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;As a tool for intermediate proof steps, e.g., &lt;code&gt;have h := by distinguish&lt;&#x2F;code&gt;, or &lt;code&gt;separate at distinctABC&lt;&#x2F;code&gt; (where
&lt;code&gt;distinctABC : distinct A B C&lt;&#x2F;code&gt;), or even &lt;code&gt;separate&lt;&#x2F;code&gt; to separate a goal of &lt;code&gt;distinct A B C ...&lt;&#x2F;code&gt; into a conjunction of
inequalities.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;To do this, we must dive into the darkest magic of this whole thing, the &lt;code&gt;syntax&lt;&#x2F;code&gt; and &lt;code&gt;elab&lt;&#x2F;code&gt; APIs. The first two items
are easy, they just construct the &lt;code&gt;Distinct&lt;&#x2F;code&gt; structure while eliding the need for brackets and commas (in the case of
&lt;code&gt;distinct&lt;&#x2F;code&gt;, which I showed at the beginning):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- Custom &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax for&lt;&#x2F;span&gt;&lt;span&gt; distinct&#x2F;distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;declare_syntax_cat&lt;&#x2F;span&gt;&lt;span&gt; distinct_binder&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax&lt;&#x2F;span&gt;&lt;span&gt; ident+ &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot; : &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; term : distinct_binder&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;distinct&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ident+ : term&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;macro_rules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | `(distinct $xs*) =&amp;gt; `(Distinct [$xs,*])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;distinguish&lt;&#x2F;code&gt; tactic just runs the &lt;code&gt;runDistinct&lt;&#x2F;code&gt; function&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;distinguish&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; : tactic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;macro_rules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | `(tactic| distinguish) =&amp;gt; `(tactic| run_tac runDistinct)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But the last item, &lt;code&gt;separate&lt;&#x2F;code&gt;, which deals with destructuring a &lt;code&gt;distinct&lt;&#x2F;code&gt; goal or fact into its constituent inequalities is… well it’s a lot.&lt;&#x2F;p&gt;
&lt;p&gt;This is definitely the most hobbled-together, hasty and unkempt part of this whole thing, so strap in:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;-- Extract points from a List Expr at the meta level -&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;partial&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; extractPoints&lt;&#x2F;span&gt;&lt;span&gt; (e : Expr) : List Expr :=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span&gt; e.isAppOfArity ``List.cons &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; head := e.appFn!.appArg!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; tail := e.appArg!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    head :: extractPoints tail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;syntax&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;separate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot; at &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ident)? : tactic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This quick helper just gets the list of Exprs inside a list, those exprs need to get pairwise connected into a
conjunction of inequality statements. I also declare the syntax to accept &lt;code&gt;separate&lt;&#x2F;code&gt; and &lt;code&gt;separate at h&lt;&#x2F;code&gt;, where &lt;code&gt;h&lt;&#x2F;code&gt; is
some fact in the context. Then I use the &lt;code&gt;elab_rules&lt;&#x2F;code&gt; to create a macro expansion. &lt;code&gt;elab_rules&lt;&#x2F;code&gt; is similar to
&lt;code&gt;macro_rules&lt;&#x2F;code&gt;, but is much more powerful, quoting the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;leanprover-community.github.io&#x2F;lean4-metaprogramming-book&#x2F;main&#x2F;02_overview.html#assigning-meaning-macro-vs-elaboration&quot;&gt;&lt;em&gt;Lean Metaprogramming
Guide&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In principle, you can do with a macro (almost?) anything you can do with the elab function. Just write what you would
have in the body of your elab as a syntax within macro. However, the rule of thumb here is to only use macros when the
conversion is simple and truly feels elementary to the point of aliasing. As Henrik Böving puts it: “as soon as types
or control flow is involved a macro is probably not reasonable anymore”.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;code&gt;separate&lt;&#x2F;code&gt; has types and control flow, so we’re above a macro; and the only thing above a macro is elab. The rules break
into two parts, the &lt;code&gt;at h&lt;&#x2F;code&gt; side is handled first, goal side (which is simpler) is second. The main difference is the
first branch needs to name individual hypotheses it’s adding to the local context, while the second just needs to
introduce new goals. I suspect there is more refactoring here, but I’ll explain it as it is; take a look at the whole
thing:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;elab_rules&lt;&#x2F;span&gt;&lt;span&gt; : tactic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | `(tactic| separate $[at $h]?) =&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  match&lt;&#x2F;span&gt;&lt;span&gt; h &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | some hId =&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      withMainContext &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; hExpr ← elabTerm hId none&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; hType ← instantiateMVars (← inferType hExpr)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; hType ← whnf hType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; !hType.isAppOfArity ``Distinct &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;separate: {hId} is not a `Distinct` hypothesis&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; some points ← Distinct.getPointsExpr hExpr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          | &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;separate: could not extract points from {hId}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; [:points.length] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          for&lt;&#x2F;span&gt;&lt;span&gt; j &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; [i+&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:points.length] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; pi := points[i]!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; pj := points[j]!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; ineqType ← mkAppM ``Ne #[pi, pj]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; ineqStx ← PrettyPrinter.delab ineqType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            -- Build a name like `AneB` &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span&gt; the fvar usernames&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; iName := (← FVarId.getUserName pi.fvarId!).toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; jName := (← FVarId.getUserName pj.fvarId!).toString&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; hypName := mkIdent (Name.mkSimple (iName ++ &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;ne&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ++ jName))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            evalTactic (← `(tactic|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;              have&lt;&#x2F;span&gt;&lt;span&gt; $hypName : $ineqStx := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                have&lt;&#x2F;span&gt;&lt;span&gt; hp := ($hId).pairwise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                simp only [List.pairwise_cons, List.mem_cons, List.mem_singleton,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           List.not_mem_nil, List.Pairwise.nil] at hp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                aesop))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | none =&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      withMainContext &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goal ← getMainGoal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← instantiateMVars (← goal.getType)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← whnf goalType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; !goalType.isAppOfArity ``Distinct &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;separate: goal is not of the form `Distinct [...]`&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; listExpr := goalType.getArg! &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; points := extractPoints listExpr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        evalTactic (← `(tactic| apply Distinct.mk))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span&gt; _ &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; [:points.length] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          try&lt;&#x2F;span&gt;&lt;span&gt; evalTactic (← `(tactic| rw [List.pairwise_cons]))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          catch&lt;&#x2F;span&gt;&lt;span&gt; _ =&amp;gt; pure ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        evalTactic (← `(tactic| simp only [List.mem_cons, List.mem_singleton, List.Pairwise.nil,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                            List.not_mem_nil, forall_eq_or_imp, forall_eq,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                            forall_const, IsEmpty.forall_iff, forall_true_iff,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                            and_true, true_and, and_assoc] at *))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        try&lt;&#x2F;span&gt;&lt;span&gt; evalTactic (← `(tactic| exact List.Pairwise.nil))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        catch&lt;&#x2F;span&gt;&lt;span&gt; _ =&amp;gt; pure ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;notice the &lt;code&gt;at h&lt;&#x2F;code&gt; side uses &lt;code&gt;simp&lt;&#x2F;code&gt; and &lt;code&gt;aesop&lt;&#x2F;code&gt;, whereas the goal side is just &lt;code&gt;simp&lt;&#x2F;code&gt;. Additionally, I restricted &lt;code&gt;simp&lt;&#x2F;code&gt;
to a fixed list of theorems; which can help address the performance issues. In both cases the &lt;code&gt;simp&lt;&#x2F;code&gt; flattens out the
goal into a series of inequalities, and the &lt;code&gt;aesop&lt;&#x2F;code&gt; line will then close the inequalities.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll focus at the second half, as it’s easy to explain:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      withMainContext &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goal ← getMainGoal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← instantiateMVars (← goal.getType)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; goalType ← whnf goalType&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; !goalType.isAppOfArity ``Distinct &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          throwError&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;separate: goal is not of the form `Distinct [...]`&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; listExpr := goalType.getArg! &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; points := extractPoints listExpr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        evalTactic (← `(tactic| apply Distinct.mk))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span&gt; _ &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; [:points.length] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          try&lt;&#x2F;span&gt;&lt;span&gt; evalTactic (← `(tactic| rw [List.pairwise_cons]))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          catch&lt;&#x2F;span&gt;&lt;span&gt; _ =&amp;gt; pure ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        evalTactic (← `(tactic| simp only [List.mem_cons, List.mem_singleton, List.Pairwise.nil,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                            List.not_mem_nil, forall_eq_or_imp, forall_eq,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                            forall_const, IsEmpty.forall_iff, forall_true_iff,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                            and_true, true_and, and_assoc] at *))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        try&lt;&#x2F;span&gt;&lt;span&gt; evalTactic (← `(tactic| exact List.Pairwise.nil))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        catch&lt;&#x2F;span&gt;&lt;span&gt; _ =&amp;gt; pure ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is similar to the &lt;code&gt;runDistinct&lt;&#x2F;code&gt; function – I grab the context, and look at the goal. I’m going to ‘prove’ this
goal by reducing it from a ‘prove this conjunction’ to ‘the conjunction is proved only if its constituent terms are
proved’. To do that, I instantiate the MVar and inspect its type, apply a &lt;code&gt;whnf&lt;&#x2F;code&gt; to ensure it’s in a normal form, and then
verify it is indeed a &lt;code&gt;distinct&lt;&#x2F;code&gt; goal with the same arity method as &lt;code&gt;runDistinct&lt;&#x2F;code&gt;. Worth noting &lt;code&gt;whnf&lt;&#x2F;code&gt; is another
recursive tool which can have similar recursion depth issues, though it’s less susceptible in my experience.&lt;&#x2F;p&gt;
&lt;p&gt;Next, I grab the list of points via the &lt;code&gt;extractPoints&lt;&#x2F;code&gt; helper, and walk over each one, rewriting with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;@[simp]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; theorem&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pairwise_cons&lt;&#x2F;span&gt;&lt;span&gt; : Pairwise R (a::l) ↔ (∀ a&amp;#39;, a&amp;#39; ∈ l → R a a&amp;#39;) ∧ Pairwise R l :=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which says, “If an item is in a &lt;code&gt;List.Pairwise R&lt;&#x2F;code&gt;, then it has the relationship &lt;code&gt;R&lt;&#x2F;code&gt; with all other items in the pairwise
relationship following its position in the list”&lt;&#x2F;p&gt;
&lt;p&gt;If this fails for any reason, the point is skipped and we won’t be able to prove everything, but that case is actually
impossible; because we know the list is only items in a pairwise relationship anyway. The last &lt;code&gt;try evalTactic&lt;&#x2F;code&gt; covers a
case where there aren’t enough elements in the distinct set, and in this case if the tactic fails we don’t care, it’s a
convenience to not have loose, trivial goals floating around.&lt;&#x2F;p&gt;
&lt;p&gt;All that, ultimately, allows for this to work:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : A ≠ B ∧ A ≠ C ∧ B ≠ C -&amp;gt; distinct A B C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro ⟨AneB, AneC, BneC⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  separate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exact ⟨AneB, AneC, BneC⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : D ≠ A ∧ D ≠ B ∧ D ≠ C -&amp;gt; distinct A B C -&amp;gt; distinct A B C D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro ⟨DneA, DneB, DneC⟩ distinctABC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  separate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  repeat&lt;&#x2F;span&gt;&lt;span&gt; tauto -- tauto covers the .symm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : D ≠ A ∧ D ≠ B ∧ D ≠ C -&amp;gt; distinct A B C -&amp;gt; distinct A B C D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro ⟨DneA, DneB, DneC⟩ distinctABC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  separate at distinctABC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  separate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  repeat&lt;&#x2F;span&gt;&lt;span&gt; tauto -- tauto covers the .symm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;effect-on-the-initial-exercise&quot;&gt;Effect on the initial exercise&lt;&#x2F;h1&gt;
&lt;p&gt;This was the original:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;-- p146. Given A-B-C and A-C-D:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;  (a) Prove that A,B,C, and D are four distinct points (the proof requires an axiom)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;-&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;theorem&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Ex1.a&lt;&#x2F;span&gt;&lt;span&gt; : A - B - C ∧ A - C - D -&amp;gt; distinct A B C D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro ⟨ABC, ACD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; distinctABC := Betweenness.abc_imp_distinct ABC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; distinctACD := Betweenness.abc_imp_distinct ACD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  simp only [ne_eq, List.pairwise_cons, List.mem_cons, List.not_mem_nil, or_false, forall_eq_or_imp,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    forall_eq, IsEmpty.forall_iff, implies_true, List.Pairwise.nil, and_self, and_true]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; AneB : A ≠ B := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctABC A B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; AneC : A ≠ C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctABC A C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; BneC : B ≠ C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctABC B C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; AneD : A ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctACD A D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; CneD : C ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctACD C D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  refine ⟨⟨AneB, AneC, AneD⟩, ⟨BneC, ?_⟩, CneD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -- &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;have&lt;&#x2F;span&gt;&lt;span&gt; BneD : B ≠ D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; distinguish distinctACD B D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  by_contra! BeqD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  rw [&amp;lt;- BeqD] at ACD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exact Betweenness.absurdity_abc_acb ⟨ABC, ACD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To be honest, this isn’t too bad, but it is a little bad; the &lt;code&gt;simp&lt;&#x2F;code&gt; line is ugly, the &lt;code&gt;have&lt;&#x2F;code&gt;s are a little unsightly,
and I have to hand-hold the old tactic a lot to get it to work. This &lt;em&gt;should&lt;&#x2F;em&gt; be simple to conclude, and that’s what
&lt;code&gt;distinguish&lt;&#x2F;code&gt; is for, here it is after all that work:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;-- p146. Given A-B-C and A-C-D:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;  (a) Prove that A,B,C, and D are four distinct points (the proof requires an axiom)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;-&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;theorem&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Ex1.a&lt;&#x2F;span&gt;&lt;span&gt; : A - B - C ∧ A - C - D -&amp;gt; distinct A B C D := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro ⟨ABC, ACD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; distinctABC := Betweenness.abc_imp_distinct ABC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  have&lt;&#x2F;span&gt;&lt;span&gt; distinctACD := Betweenness.abc_imp_distinct ACD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -- The majority of cases are handled &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt; the custom tactics&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  separate; distinguish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -- The remaining case is to disprove BeqD under the betweenness hypotheses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  by_contra! BeqD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  rw [&amp;lt;- BeqD] at ACD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exact Betweenness.absurdity_abc_acb ⟨ABC, ACD⟩&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Much&lt;&#x2F;em&gt; nicer. I can grab a couple distinctness hypotheses using existing theorems about Betweenness of points. I then &lt;code&gt;separate&lt;&#x2F;code&gt; the main goal into a list of inequalities like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A ≠ B ∧ A ≠ C ∧ A ≠ D ∧ B ≠ C ∧ B ≠ D ∧ C ≠ D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;most of which are dispatched by the &lt;code&gt;distinguish&lt;&#x2F;code&gt; command immediately following it. The only remaining case is that &lt;code&gt;B&lt;&#x2F;code&gt;
and &lt;code&gt;D&lt;&#x2F;code&gt; are distinct, which is easy to prove by contradiction and a known absurdity.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-s-left&quot;&gt;What’s left&lt;&#x2F;h1&gt;
&lt;p&gt;There are a lot of improvements to make, I think; my use of the &lt;code&gt;elab&lt;&#x2F;code&gt; facilities is pretty naive, and I think a lot
could be cleaned up if I had a better understanding of the API, but no progress without practice, and this really
simplifies a lot of annoying bookkeeping. The fact that the syntax is so directly adjustable and easy to extend and
tweak is really satisfying. I spent a lot of time writing Ruby, and the reason I liked it was really down to how easy it
was to get the interpreter to read the way I wanted. Lean is that but with even more flexibility and a really powerful
API for both extending the language and also manipulating the proof state. Since the language is so focused on the proof
state anyway, being able to automate the interactions really feels like a superpower. Truly cool stuff.&lt;&#x2F;p&gt;
&lt;p&gt;I have some plans to add lemmas around how to extend the &lt;code&gt;distinct&lt;&#x2F;code&gt; condition, ‘adding’ a point to the condition
requires a proof that the new item is distinct from all other items, which is a goal-state that should be automatable to
create, but would certainly be a pain to do by hand. Removing items from a &lt;code&gt;distinct&lt;&#x2F;code&gt; condition is comparatively easy
(it requires no real ‘proof’), but proving a general theorem that doesn’t regard the length of the list is a little
tricky.&lt;&#x2F;p&gt;
&lt;p&gt;I also have another condition, &lt;code&gt;collinear&lt;&#x2F;code&gt;, that needs similar syntactic treatment, and probably some custom tactics as
well.&lt;&#x2F;p&gt;
&lt;p&gt;There is also, of course, extending &lt;code&gt;distinguish&lt;&#x2F;code&gt; and &lt;code&gt;separate&lt;&#x2F;code&gt; to look past disjunctions and quantifiers to try to
resolve goals.&lt;&#x2F;p&gt;
&lt;p&gt;One thing I didn’t mention was the &lt;code&gt;delaborator&lt;&#x2F;code&gt;. I didn’t talk about it mostly because I barely understand it, but it’s
similar to a prettyprinter. It helps display facts and goals in a ‘nice’ way. Right now the facts look like &lt;code&gt;Distinct [A, B, C]&lt;&#x2F;code&gt;, not &lt;code&gt;distinct A B C&lt;&#x2F;code&gt;, which is not &lt;em&gt;too&lt;&#x2F;em&gt; confusing, but originally they looked like &lt;code&gt;distinctABC : List.Pairwise (· ≠ ·) [A, B, C]&lt;&#x2F;code&gt; which &lt;em&gt;was&lt;&#x2F;em&gt; pretty weird, the delaborator is the thing that fixes that, I think; I
haven’t really dug in.&lt;&#x2F;p&gt;
&lt;p&gt;It’d also be nice to grab other known inequality-related facts and try to use those, or reassemble things back down to a
single goal after splitting; these are quality-of-life things. It’s often the case that you’ll have a couple spare facts
floating around that could resolve more goals, but &lt;code&gt;distinguish&lt;&#x2F;code&gt; will ignore them, or you’ll have a fact like &lt;code&gt;h : (∀ P : Nat, P = 3 -&amp;gt; P &amp;gt; 1) ∧ (C ≠ D ∨ V = W)&lt;&#x2F;code&gt;, and if you end up with a pair of goals you have to resolve them across two
lines with &lt;code&gt;exact h.left; exact h.right&lt;&#x2F;code&gt; instead of just &lt;code&gt;exact h&lt;&#x2F;code&gt;. Low frequency, but possible.&lt;&#x2F;p&gt;
&lt;p&gt;But overall that’s it. That’s how it works. It’s just a Monad. It’s got a little scripting language in it, and now I’ve
taken about ~2000 words more than the LTPG to explain the same things but worse, but it was fun to do it and that’s what
matters.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for nudging me towards writing about it.&lt;&#x2F;p&gt;
&lt;p&gt;&#x2F;Joe&lt;&#x2F;p&gt;
&lt;p&gt;P.S.&lt;&#x2F;p&gt;
&lt;p&gt;A stunning addendum to my suggested trichotomy of things a keyword might operate on – another has been found!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lean&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt; : distinct A B C D -&amp;gt; distinct A B C := &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  intro dABCD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exact dABCD forgetting D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is like a little wrapped up proof, similar to the &lt;code&gt;distinguish&lt;&#x2F;code&gt; proof, but instead of being a tactic it’s a sort of
term-mode operator. The implementation works for both &lt;code&gt;collinear&lt;&#x2F;code&gt; and &lt;code&gt;distinct&lt;&#x2F;code&gt; by doing type-dispatch in the
elaboration step. It constructs the proof dynamically, similar to &lt;code&gt;distinguish&lt;&#x2F;code&gt;, but without needing &lt;code&gt;aesop&lt;&#x2F;code&gt;, which is
pretty handy. Operators on proof terms like this is a whole other world I hadn’t considered for syntax trickery. Lean is
so cool.&lt;&#x2F;p&gt;
&lt;p&gt;P.P.S. (13-MAY-2026)&lt;&#x2F;p&gt;
&lt;p&gt;I got distracted and left this project alone for a bit, but coming back to it, I noticed an interesting,
mostly-unrelated-to-syntax-hacking thing that needed a place to live.&lt;&#x2F;p&gt;
&lt;p&gt;The project this repo encapsulates is one of in-place formalization, trying to capture Greenberg’s original argument &lt;em&gt;as
made&lt;&#x2F;em&gt; instead of the most idiomatic Lean formalization of the fact. Terence Tao makes a similar caveat in his &lt;em&gt;Analysis&lt;&#x2F;em&gt;
project:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The files in this directory contain a formalization of my text Analysis I into Lean. The formalization is intended to
be &lt;strong&gt;as faithful a paraphrasing as possible to the original text&lt;&#x2F;strong&gt;, while also showcasing Lean’s features and syntax. In
particular, the formalization is not optimized for efficiency, and &lt;strong&gt;in some cases may deviate from idiomatic Lean
usage.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;teorth&#x2F;analysis&#x2F;blob&#x2F;main&#x2F;README.md&quot;&gt;README.md of teorth&#x2F;analysis&lt;&#x2F;a&gt;, emph mine&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I ran into a similar issue with P3.3, which uses (as I ultimately extracted in &lt;code&gt;Intersection.between_splits&lt;&#x2F;code&gt;) the
converse of &lt;code&gt;Intersection.splits_points&lt;&#x2F;code&gt; to dispatch which points end up on which side of the splitting line to
construct, ultimately, (most of) the apparatus needed to define an arbitrary &lt;code&gt;A - B - ... - Z&lt;&#x2F;code&gt; betweenness
specification. This is its own little syntax rabbit warren to explore, but what was really interesting was the decision
point in how I’m formalizing Greenberg.&lt;&#x2F;p&gt;
&lt;p&gt;On the one hand, if I were to formalize a theory of Geometry in Lean, I don’t think I’d pick this text to work from.
This makes some sense, Greenberg wasn’t optimizing to be formalized, he was optimizing for human intuition. As such, he
relies occasionally on ‘big’ (in the sense of # of lines of Lean) steps that are deeply &lt;em&gt;intuitive&lt;&#x2F;em&gt;, but frustrating to
formalize.&lt;&#x2F;p&gt;
&lt;p&gt;There’s been a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rkirov.github.io&#x2F;posts&#x2F;three-cultures-of-math&#x2F;&quot;&gt;lot&lt;&#x2F;a&gt; of
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;davidbessis.substack.com&#x2F;p&#x2F;the-fall-of-the-theorem-economy&quot;&gt;talk&lt;&#x2F;a&gt; recently about
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;terrytao.wordpress.com&#x2F;2026&#x2F;05&#x2F;03&#x2F;primitive-sets-and-von-mangoldt-chains-erdos-problem-1196-and-beyond&#x2F;&quot;&gt;how&lt;&#x2F;a&gt;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gowers.wordpress.com&#x2F;2026&#x2F;05&#x2F;08&#x2F;a-recent-experience-with-chatgpt-5-5-pro&#x2F;&quot;&gt;LLMs&#x2F;Agents&#x2F;“AI”&lt;&#x2F;a&gt; are going to
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cdn.openai.com&#x2F;pdf&#x2F;6dc7175d-d9e7-4b8d-96b8-48fe5798cd5b&#x2F;Ramsey.pdf&quot;&gt;obsoletize&lt;&#x2F;a&gt; us in the context of
mathematics. I think this distinction points at a specific place where, at least for now, it can’t.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve worked a little bit here with some LLM tools; and while I was, at first, extremely antagonistic (irrationally so)
about them, I think I’m coming around a bit. In working on refactoring out that lemma, in particular, it did a great job
of immediately spotting and extracting the common lemma (which makes sense, it wasn’t hard to spot the duplication, just
a little tricky to extract amidst all the tactics). Probing it even a little made it clear that the process was
mechanical and it had no &lt;em&gt;intuition&lt;&#x2F;em&gt; for the structure, just the ability to see the pattern and extract it.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up in a conundrum: how much do I leave in the proof to mimic Greenberg’s initial argument, which relies on a
deeply intuitive and natural conclusion, but which – at least in the context of my abilities with Lean – is not a
trivial conclusion, and how much do I refactor to make the argument ‘nice’? On the one hand, my goal is to line-for-line
confirm the original arguments, filling in the areas that were not ‘fully rigorous’ (as far as you trust Lean, anyway),
and not necessarily to write ‘good Lean’ necessarily that has the kinds of qualities we might look for in a standard
codebase (e.g., Mathlib). No shade to the standards, I’m just a novice and I only learn by making all the mistakes
myself.&lt;&#x2F;p&gt;
&lt;p&gt;I offer no conclusion or deeper insight other than to say my solution was to punt as hard and far as I could. I left the
original argument intact on one branch, and used (or plan to use, at time-of-writing I have two corollaries left to
prove) the extracted &lt;code&gt;between_splits&lt;&#x2F;code&gt; lemma on the others, but I think it’s interesting to note that; while we may be
able to ‘harvest the overhang’ as David Bessis put it in his article linked above, the consequence is not merely a loss
of the ‘Theorem Economy’, but that since this will give us &lt;em&gt;only&lt;&#x2F;em&gt; the factored, narrow, intuition-free proofs; I’m not
even sure how useful the result would really be to understanding mathematics more deeply. The &lt;em&gt;point&lt;&#x2F;em&gt; of all of this is
to find the ‘big but intuitive’ jumps that we can use not just here, but elsewhere. The jump that Greenberg makes is one
that requires the reader to grab for the intuition that ‘betweenness’ is really just a kind of ordered listing of the
names of points. It points towards a lighthouse far in the distance and says “This ship will sail us all the way to
where Dedekind was when he made his cuts.” I don’t think this small lemma would be enough to break the intuition, but it
certainly shortens its long gaze, and if I focused instead on the particular arrangement of lines and halyards, I’d’ve
missed seeing the shoreline approaching, and that seems like more than just a simple mechanical disaster; it seems more
like we’re building a tunnel through mathematics to get to the destination, with no concern for what we missed on our
long, boring drive there. That makes me sad.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Of course, this is equal parts real – I do mean this as a direct letter to you; but also it’s just going to be
stuck in the repo and anyone’ll be able to read it, and I’ve written explanations of stuff I’m sure you already know
well from experience with Haskell and the like, so it’s still also kind of a blog post? Left as an exercise to the
reader. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;It is, of course &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;leanprover-community.github.io&#x2F;lean4-metaprogramming-book&#x2F;main&#x2F;02_overview.html#manual-conversions-between-syntaxexprexecutable-code&quot;&gt;more complicated than
that&lt;&#x2F;a&gt;.
You can bypass Expr. You can convert things back and forth. The parser is &lt;em&gt;extremely&lt;&#x2F;em&gt; flexible. &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;This is a lie, I started in a much less structured way that mostly involved me copying large chunks of Mathlib and
hitting it with my face until it mostly worked. I cannot emphasize enough how far from comprehension some of this is to
me; it’s delightful. &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;I am &lt;em&gt;positive&lt;&#x2F;em&gt; there is a cleaner way to do this; I don’t know what it is, but I’m sure that spending more time
building up a better structure over the proof would help simplify the monster here, but the critical thing is this does
work for most of what I need, and so the tyranny of the local optimum is &lt;em&gt;definitely&lt;&#x2F;em&gt; going to win. &lt;a href=&quot;#fr-4-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2-MAR-2026</title>
        <published>2026-03-02T00:00:00+00:00</published>
        <updated>2026-03-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/2-mar-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/2-mar-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/2-mar-2026/">&lt;h2 id=&quot;2145&quot;&gt;2145&lt;&#x2F;h2&gt;
&lt;p&gt;Got &lt;code&gt;distinguish&lt;&#x2F;code&gt; working, I need a lemma, though, to decompose a &lt;code&gt;distinct&lt;&#x2F;code&gt; term in the goal to it’s relevant ineq
goals; and then I get to do more repairs on proofs to get them running again. The &lt;code&gt;distinguish&lt;&#x2F;code&gt; stuff was certainly a
trip to get working; it’s simultaneously very easy and very hard to think about metaprogramming Lean. &lt;code&gt;collinear&lt;&#x2F;code&gt; is
going to be another headtrip, I think.&lt;&#x2F;p&gt;
&lt;p&gt;Skunks are out, though, so spring is coming soon; and spring means open windows, and open windows are good for math.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>28-FEB-2026</title>
        <published>2026-02-28T00:00:00+00:00</published>
        <updated>2026-02-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/28-feb-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/28-feb-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/28-feb-2026/">&lt;h2 id=&quot;2220&quot;&gt;2220&lt;&#x2F;h2&gt;
&lt;p&gt;I’m getting into the weeds of API design here and I’m finding an increasing need to learn how to actually use the Elab
and stop cobbling together snippets and screwing around until I get it working. There’s a cool project about
metaprogramming in Lean which is itself a lean project, so I might take a little time and go through that.&lt;&#x2F;p&gt;
&lt;p&gt;The main struggle right now is with coercing lean into an ergonomic API for talking about &lt;code&gt;distinct&lt;&#x2F;code&gt; points and
&lt;code&gt;collinear&lt;&#x2F;code&gt; points; in particular, I’d like to have theorems that are something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;distinct A B C ... &#x2F;\ D =&#x2F;= ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I decided I’d talk about this in a vlog, so if I ever post that anywhere I’ll edit a link in here.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-FEB-2026</title>
        <published>2026-02-27T00:00:00+00:00</published>
        <updated>2026-02-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/27-feb-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/27-feb-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/27-feb-2026/">&lt;h2 id=&quot;0041&quot;&gt;0041&lt;&#x2F;h2&gt;
&lt;p&gt;Working with collinearity is a pain; I currently have it limited to a triple, so reasoning about larger bodies of
collinear points is a pain (I have to manually extract the induced line for each triple and manually correlate them). I
have a similar problem with &lt;code&gt;distinct&lt;&#x2F;code&gt;, which is for pairwise distinct things-with-equality.&lt;&#x2F;p&gt;
&lt;p&gt;I need to build some better tools for reasoning about these, because it makes proofs a pain to follow and is a common
place where I burn &lt;code&gt;tauto&lt;&#x2F;code&gt; time.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-FEB-2026</title>
        <published>2026-02-26T00:00:00+00:00</published>
        <updated>2026-02-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/26-feb-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/26-feb-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/26-feb-2026/">&lt;h2 id=&quot;2145&quot;&gt;2145&lt;&#x2F;h2&gt;
&lt;p&gt;I’m making good headway on formalizing Greenberg’s proof of 3.3; there was mostly just small stuff missing; my proof of
step (5) is close to done, but the proof is quite big as a result, and it’s a conjuction of two similar but very
slightly different arguments that is going to be hard to &lt;code&gt;suffice&lt;&#x2F;code&gt; away.&lt;&#x2F;p&gt;
&lt;p&gt;I also ran into a new problem, speed. I made liberal use of &lt;code&gt;tauto&lt;&#x2F;code&gt; across this code base and it is starting to hurt.
It’s mostly just laziness and a misunderstanding of cost; I’ve started taking it out where possible. I’ll need to add
another script (or maybe a lint) to count these and chase them away. I’ll also need to add a profile step to the CI. The
stats it produces are pretty basic, but it’s more than enough to chase away performance blowups. The issue does seem
local to the proof (which makes sense, as it’s essentially just hammering away using the available hypothesis, which
don’t cut across proofs), it’s interesting how proof complexity becomes a performance hazard; you lose a powerful tool
when the proof is too large. Even if you don’t intend to keep the tauto, knowing that your environment has all the
equipment needed to finish the proof is quite useful, and if the proof is so complex that tauto takes forever, you are
essentially blinded by your own inefficiency.&lt;&#x2F;p&gt;
&lt;p&gt;Refactoring has always felt like an ‘elegant’ thing to do; and it’s neat to see that mathematical parsimony, clever
argument, and smart lemma choices; things that feel themselves like elegance, are directly correlated with each other in
such a nice way.&lt;&#x2F;p&gt;
&lt;p&gt;I fucking love math.&lt;&#x2F;p&gt;
&lt;p&gt;Going to take a break from 3.3 and clean up tautos for a few commits.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>25-FEB-2026</title>
        <published>2026-02-25T00:00:00+00:00</published>
        <updated>2026-02-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/geometry-is-your-friend/25-feb-2026/"/>
        <id>https://disturbed-circles.com/log/geometry-is-your-friend/25-feb-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/geometry-is-your-friend/25-feb-2026/">&lt;h2 id=&quot;0028&quot;&gt;0028&lt;&#x2F;h2&gt;
&lt;p&gt;I can’t believe I didn’t have this going already.&lt;&#x2F;p&gt;
&lt;p&gt;I’m trying to reorganize things a bit. I have a huge pile of general theory that I had to build up to formalize 3.2, and
I learned a bunch about the namespace system, and I have a rough idea of what I want to do, but I’m trying to think of
the best way to structure things.&lt;&#x2F;p&gt;
&lt;p&gt;My current setup has&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ChX&#x2F; -- directory per chapter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Prop&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            PY.lean -- file per proposition and related correlaries. Currently contains a bunch of loose theory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Ex&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ExZ.lean -- file per exercise (if multipart, it&amp;#39;s all here).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Prop.lean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Ex.lean&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        README.md&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Theory&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Concept&#x2F; -- A directory for each &amp;quot;Concept&amp;quot;, e.g., Line, Betweenness, Collinearity, Intersection, etc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ChX.lean -- A file for all the general theory needed for that chapter. May depend on previous chapters.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ChX&#x2F; -- if there is a directory, ChX.lean should exist to bring in it&amp;#39;s contents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Syntax.lean -- any custom syntax I need at the topmost level, mostly empty&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Tactics.lean -- imports mathlib tactics&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Theory.lean -- imports everything, main entry point to the theory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Geometry.lean -- pulls in the chapter propositions and exercises via the `Prop.lean`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This mostly lets me interleave and get all the ordering right, but it’s a bear to build the main import file
(Theory.lean) because the order of the tree is wrong, chapters should parent concepts, but then I have the opposite
problem in the directory structure – I have to replicate the concept folders over and over.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;really&lt;&#x2F;em&gt; wish that lean just jammed everything into a database, workedout the dependencies, and complained when it
couldn’t. Maybe the module system will fix this? I haven’t really looked too much into it except for my initial attempt,
I’ll have to investigate.&lt;&#x2F;p&gt;
&lt;p&gt;For now I suppose I can write a script to generate the theory file.&lt;&#x2F;p&gt;
&lt;p&gt;I added a flake.nix and set up python, so I suppose I’ll use that. I saw the blueprint tool uses python to interact with
the lean code to generate the graphviz file, so maybe I can crib from them a bit.&lt;&#x2F;p&gt;
&lt;p&gt;Unrelated, it’d be very cool to build some kind of geogebra&#x2F;lean connection (maybe using
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leanprover-community&#x2F;ProofWidgets4&quot;&gt;proofwidgets&lt;&#x2F;a&gt;?), not sure the feasibility (especially since I’m
not on vscode which I suspect is required, but haven’t found an explicit statement thereof).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2235&quot;&gt;2235&lt;&#x2F;h2&gt;
&lt;p&gt;I got pretty much everything reorganized, it wasn’t &lt;em&gt;too&lt;&#x2F;em&gt; painful. I also rewrote a bunch of proofs in a much nicer way;
in particular &lt;code&gt;Line.line_trichotomy&lt;&#x2F;code&gt; is a really handy tool.&lt;&#x2F;p&gt;
&lt;p&gt;The debate now is whether I’m going to automate generating the Geometry.lean and Theory.lean files; and more generally
it’d be nice to have some scaffolding scripts for creating new chapters&#x2F;etc in the correct structure. I had a &lt;code&gt;ChX&lt;&#x2F;code&gt;
chapter-template, but I wasn’t sure what I was doing when I originally made it. The things I’d like some kind of
template&#x2F;script for are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Constructing the Geometry.lean, which includes all the actual chapters&lt;&#x2F;li&gt;
&lt;li&gt;Constructing the Theory.lean, which is where all the general theory and lemmas go&lt;&#x2F;li&gt;
&lt;li&gt;Constructing the &lt;code&gt;web&lt;&#x2F;code&gt; and &lt;code&gt;print&lt;&#x2F;code&gt; blueprint files via some introspection over all the theorems&#x2F;lemmas in the
codebase&lt;&#x2F;li&gt;
&lt;li&gt;Creating a new chapter&#x2F;theory section according to whatever strictures I need.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I don’t think I’m going to do this now, I’d like to get back to proving, but something to think on.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>6-JAN-2026</title>
        <published>2026-01-06T00:00:00+00:00</published>
        <updated>2026-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/6-jan-2026/"/>
        <id>https://disturbed-circles.com/log/truncheon/6-jan-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/6-jan-2026/">&lt;h2 id=&quot;1337&quot;&gt;1337&lt;&#x2F;h2&gt;
&lt;p&gt;lmao funny number.&lt;&#x2F;p&gt;
&lt;p&gt;I have the initial input handler more or less working, I need to commit off what I have for the image pipeline side so
it’s saved somewhere then remove it.&lt;&#x2F;p&gt;
&lt;p&gt;A critical next step is building a better build&#x2F;test&#x2F;repeat loop. I’ve been sitting on this work for a while because
testing it feels bad, lots of waiting, lots of actions-per-loop.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;bevy_testing&lt;&#x2F;code&gt; and headless mode are probably the way to go, but it’d be cool if I can do some amount of input testing,
maybe get insta working somehow, not sure.&lt;&#x2F;p&gt;
&lt;p&gt;Hot code reloading would be nice but I don’t want to fight through the ratatui component of things to get it working.&lt;&#x2F;p&gt;
&lt;p&gt;I’m leaning towards refactoring the input manager to be all-bevy, then feed back to the ratatui side, but not sure if
that makes sense yet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1-JAN-2026</title>
        <published>2026-01-01T00:00:00+00:00</published>
        <updated>2026-01-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/1-jan-2026/"/>
        <id>https://disturbed-circles.com/log/truncheon/1-jan-2026/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/1-jan-2026/">&lt;h2 id=&quot;1158&quot;&gt;1158&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been off working on upgrades to the editor and general improvements to my workflow, but I’ve also been reading a
bunch about climate modeling because I am constantly drawn towards the fun part and not the boring stuff it takes to get
there, which is why I’m writing this instead of getting the IO widget working. I’m going to go work on the IO widget
now, and hopefully come back and write another entry when I finish it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>29-DEC-2025</title>
        <published>2025-12-29T00:00:00+00:00</published>
        <updated>2025-12-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/29-dec-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/29-dec-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/29-dec-2025/">&lt;h2 id=&quot;1709&quot;&gt;1709&lt;&#x2F;h2&gt;
&lt;p&gt;Merged a pile of stuff into glamdring, using &lt;code&gt;edgy&lt;&#x2F;code&gt; to get some sidebars in place and make better use of the ultrawide.
The &lt;code&gt;log&lt;&#x2F;code&gt; section is pretty crap at the moment but I’m hoping I can eventually get it to scroll through and show all the
content that would otherwise be displayed via &lt;code&gt;:Notifications&lt;&#x2F;code&gt; in a buffer that auto-refreshes (a la VSCode’s version of
same).&lt;&#x2F;p&gt;
&lt;p&gt;I also set up &lt;code&gt;lean4&lt;&#x2F;code&gt; support (in principle) and stubbed in &lt;code&gt;modelica&lt;&#x2F;code&gt; support. These will be for general use and
specific use, respectively; &lt;code&gt;lean&lt;&#x2F;code&gt; just looks like a good tool to learn, and &lt;code&gt;modelica&lt;&#x2F;code&gt; is going to factor into
&lt;code&gt;truncheon&lt;&#x2F;code&gt; in short order.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>9-DEC-2025</title>
        <published>2025-12-09T00:00:00+00:00</published>
        <updated>2025-12-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/9-dec-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/9-dec-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/9-dec-2025/">&lt;h2 id=&quot;1136&quot;&gt;1136&lt;&#x2F;h2&gt;
&lt;p&gt;Got logging and the picker updating better, still having trouble with the camera widget, likely down to not
understanding exactly the scope of the ‘strategy’ system that BRC is using.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;22-dec-2025&quot;&gt;22-DEC-2025&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;1144&quot;&gt;1144&lt;&#x2F;h2&gt;
&lt;p&gt;Alright, pretty much everything is ‘working’ now, I switched back to the standard BRC output for now, with a plan to
replace with the ‘full resolution’ version in the future. For now it’s good enough to proceed with the rest of things.&lt;&#x2F;p&gt;
&lt;p&gt;I think the next steps are the following:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Input&#x2F;Command parsing&lt;&#x2F;li&gt;
&lt;li&gt;Representing “Spaces”, the first of which is probably as standard “Overlay”-based hexgrid (similar to what’s on offer
in Foundry or R20), followed by a sparse “HexTopology” – which stores individual hexes and their locations and will
(eventually) support something like WFC for generating more terrain&lt;&#x2F;li&gt;
&lt;li&gt;diagnostic components rendering in the ratatui interface – e.g., the rest of the TUI Logger widget, a proper command
IO widget, etc&lt;&#x2F;li&gt;
&lt;li&gt;Mouse integration + logged click events.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;#2 is what I’ve been chipping at, but I think #1&#x2F;#3 and to a lesser extent #4 are the better things to work on right
now, as the interaction I want to have is largely command-driven.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>8-DEC-2025</title>
        <published>2025-12-08T00:00:00+00:00</published>
        <updated>2025-12-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/8-dec-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/8-dec-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/8-dec-2025/">&lt;h2 id=&quot;1419&quot;&gt;1419&lt;&#x2F;h2&gt;
&lt;p&gt;Fighting with nixos and dioxus and bevy and friends. Makes me think of building a VM or container for just dev. NixOS is
a fantastic thing for static environments, but it’s very frustrating to use in a dev environment.&lt;&#x2F;p&gt;
&lt;p&gt;An Arch box w&#x2F; home-manager may be in the future.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>4-DEC-2025</title>
        <published>2025-12-04T00:00:00+00:00</published>
        <updated>2025-12-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/4-dec-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/4-dec-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/4-dec-2025/">&lt;h2 id=&quot;1457&quot;&gt;1457&lt;&#x2F;h2&gt;
&lt;p&gt;Feeling a bit frustrated trying to cajole &lt;code&gt;bevy_ratatui_camera&lt;&#x2F;code&gt; into &lt;code&gt;ratatui_image&lt;&#x2F;code&gt; and get something sensible to pop
out. I suspect many things, but I’ve also been thinking a bit about how to approach this if I can’t get it working at
the CLI level. In particular, getting it to run in a browser is appealing from a delivery perspective, it would be
significantly simpler to embed it as a WebGL&#x2F;WSGL + WASM binary, at which point I could ostensibly have hot-reloading as
well; it minimizes the testability to some extent (&lt;code&gt;insta&lt;&#x2F;code&gt; probably won’t work), but it would mean I could just use
&lt;code&gt;bevy&lt;&#x2F;code&gt; as intended, rather than trying to force it into a &lt;code&gt;ratatui_image&lt;&#x2F;code&gt; block.&lt;&#x2F;p&gt;
&lt;p&gt;Another alternative is to move development to be directly on dragon rather than over SSH. I like the idea of trying to
get something that uses kitty’s image protocol to do real ‘graphics’ over SSH, but I also just want the thing to work so
I can get on with the actual point of this project.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2-DEC-2025</title>
        <published>2025-12-02T00:00:00+00:00</published>
        <updated>2025-12-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/2-dec-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/2-dec-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/2-dec-2025/">&lt;h2 id=&quot;1220&quot;&gt;1220&lt;&#x2F;h2&gt;
&lt;p&gt;I’m working on getting everything organized. I decided to just drop the current state into a commit, and then start
cutting through things till I have something functional again. I’m going to rip out all the SVG stuff after that commit
as I don’t intend to use it, and I think the more I pare down the better time I’m going to have.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1-DEC-2025</title>
        <published>2025-12-01T00:00:00+00:00</published>
        <updated>2025-12-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/1-dec-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/1-dec-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/1-dec-2025/">&lt;h2 id=&quot;1334&quot;&gt;1334&lt;&#x2F;h2&gt;
&lt;p&gt;I think I have settled in on what this is, it is a campaign system. A GM of a TTRPG chooses a TTRPG system, and creates
maps&#x2F;players&#x2F;etc and then tracks their goings on via this system, which manages hex&#x2F;depth crawls, and tracks multiple
parties of both PCs and NPCs and generates “Decisions” which end up assigned to different players. Most will be left to
the GM, who can use a scripting language to make decisions automatically or intervene to make specific decisions when
they care to. Others get assigned to the players and the GM presents those decisions organically as a part of play. The
point of the system is to track the timelines of PCs and NPCs so that any individual’s history is inspectable by the GM
so that the GM can have a full understanding of how things occurred within the game world. The idea is that it provides
tools to track the tedious parts of the game, separate from any particular representation of the game. It is system
agnostic, it still requires a GM to intervene and encode the effects of decisions that players make, but it tries to
tuck away all the die rolling to generate encounters, terrain, etc, and helps track the overall difficulty of the world
and accrue details on what players are doing as they do it.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’m going to switch to using Bevy with a Ratatui frontend. I still want this to be usable via CLI, I still want
it to integrate with Foundry, though I’m less concerned with the SVG output-based approach and more interested in the
already existing bevy_ratatui and bevy_ratatui_camera, which I think cover my needs nicely.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-NOV-2025</title>
        <published>2025-11-20T00:00:00+00:00</published>
        <updated>2025-11-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/20-nov-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/20-nov-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/20-nov-2025/">&lt;h2 id=&quot;1441&quot;&gt;1441&lt;&#x2F;h2&gt;
&lt;p&gt;All of this does nothing in the face of the actual current problem which is rendering slowness, but it has been fun to
dive down the rabbit hole a bit.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-NOV-2025</title>
        <published>2025-11-19T00:00:00+00:00</published>
        <updated>2025-11-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/19-nov-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/19-nov-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/19-nov-2025/">&lt;h2 id=&quot;1220&quot;&gt;1220&lt;&#x2F;h2&gt;
&lt;p&gt;I think I have a theory of how it should work.&lt;&#x2F;p&gt;
&lt;p&gt;Each Pop and Locality is equipped with a Timeline. Timelines are sequences of a shared pool of Events which are
&lt;em&gt;Simultaneous&lt;&#x2F;em&gt; across those timelines but not necessarily across others. When an event occurs, all those present for it
mark it in their timeline as an event.&lt;&#x2F;p&gt;
&lt;p&gt;Each Locality is part of a Region, multiple Regions are part of a World, and a World has a special timeline that all
inhabitants of that World share. The World Timeline (“Worldline”) contains every event that happens in the world on a
shared reference clock; but other worlds can proceed at different paces to it. So for my setup I currently have 4
worlds:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Eret&lt;&#x2F;li&gt;
&lt;li&gt;Ynn&lt;&#x2F;li&gt;
&lt;li&gt;Stygia&lt;&#x2F;li&gt;
&lt;li&gt;The IM’s lair&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Time moves differently in Ynn, but is synced with Eret in the other cases. Each Worldline advances according to GM Fiat;
generally, instead, timelines calculate &lt;em&gt;where they should be on the other timeline&lt;&#x2F;em&gt; when travelling between worlds.
Take this simpler example:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Ratio&lt;&#x2F;th&gt;&lt;th&gt;World A&lt;&#x2F;th&gt;&lt;th&gt;World B&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;World A&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;World B&lt;&#x2F;td&gt;&lt;td&gt;0.5&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;So if a Pop is in World A, then enters World B and stays for 1 hour on world B, then returns to World A, they will
return at &lt;code&gt;T1 = T0 + 0.5h&lt;&#x2F;code&gt;, where &lt;code&gt;T0&lt;&#x2F;code&gt; is the time of the previous event on world A. If they wait an hour on A, then return to B,
they will arrive at &lt;code&gt;T1+2h&lt;&#x2F;code&gt;, or &lt;code&gt;T0+2.5h&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So long as we know the sequence of events undertaken by a Pop, we can always calculate where we should arrive on the
target timeline.&lt;&#x2F;p&gt;
&lt;p&gt;The goal is to just keep a consistent history of each Pop, the timeline of each world is just a function of the
relationship between two timeline’s clock-speed and the events which cause them to co-align. Events get tagged with the
&lt;code&gt;Locality&lt;&#x2F;code&gt; they occur in, and the Worldlines are thus calculated. An event has a &lt;code&gt;Start&lt;&#x2F;code&gt; time local to its worldline,
which will account for gaps.&lt;&#x2F;p&gt;
&lt;p&gt;This creates a final structure like this:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Universe
&lt;ul&gt;
&lt;li&gt;Eret
&lt;ul&gt;
&lt;li&gt;Upper Carpathia&lt;&#x2F;li&gt;
&lt;li&gt;Ulm&lt;&#x2F;li&gt;
&lt;li&gt;Edom&lt;&#x2F;li&gt;
&lt;li&gt;Corinth&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Ynn
&lt;ul&gt;
&lt;li&gt;3x Eret&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Stygia
&lt;ul&gt;
&lt;li&gt;1x Eret&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The IM’s Lair
&lt;ul&gt;
&lt;li&gt;1x Eret&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With connections such that Eret is the Hub, and the others are spokes, which simplifies the matrix above.&lt;&#x2F;p&gt;
&lt;p&gt;It is possible, likely even, that this will allow for paradoxes. That’s intentional. When a pardox occurs, the worlds
should split into new, independent worlds, with that Event representing the branching point. Any timeline can split.
This occurs naturally as people travel across different worlds.&lt;&#x2F;p&gt;
&lt;p&gt;This model also allows for pseudorelativistic effects between worlds, since travel is ‘instant’ inasmuch as there is no
space to travel, but the two worlds run their clocks at ‘different rates’ so things change slightly as you move ‘further
away’. The relative clock speed on Mercury, for instance, is somewhat slower than an equivalent clock on Earth, losing
about 1 minute every 50 years or so, but varying considerably in the exact rate of exchange between an terran minute and
a mercurial one. This would model that as a fixed ratio (though in actuality it is not fixed, but based on the relative
positions of the various involved bodies. A future enhancement might turn the relativity matrix above into a dynamically
calculated function, but that’d require additional work to make the various ‘worlds’ more like physical objects.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-NOV-2025</title>
        <published>2025-11-18T00:00:00+00:00</published>
        <updated>2025-11-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/18-nov-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/18-nov-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/18-nov-2025/">&lt;h2 id=&quot;1050&quot;&gt;1050&lt;&#x2F;h2&gt;
&lt;p&gt;EU V has been eating my whole life. Factorio too.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve also been thinking about this and what I want to do. Ultimately, and I recognize this is a function of having been
playing EU V pretty much nonstop since it came out, I think I want to push truncheon in the direction of having some
pop-based simulatation component. It’s not exactly EU, but it’s definitely adjacent.&lt;&#x2F;p&gt;
&lt;p&gt;The idea would be to have a few classes of ’pop’s, which would be user definable with ‘promotion rules’ between them. So
for my D&amp;amp;D campaign I might have two general classes of pops, “Mundane” and “Sorted”, with no promotion between them
(generally), and within “Sorted” I might have a subclass for each level with promotion rules about how muse “Applied
Vesper” the Sorted has acquired. As they acquire enough, they promote to the next level.&lt;&#x2F;p&gt;
&lt;p&gt;I can then make arbitrary rules for how those pops behave, move around the world, etc. Mundane pops would tend to
congregate with other Mundanes, give them logic to form villages and stuff; and have the sorted run around. Maybe
another class for Monsters, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Then I give them a big hex grid to hang around in and let them do their thing; I can still use it to track a party in
the same world, except now as they move, so does everything else.&lt;&#x2F;p&gt;
&lt;p&gt;The world would have a bunch of &lt;code&gt;Good&lt;&#x2F;code&gt;s as well, produced by the various pop classes by doing &lt;code&gt;Job&lt;&#x2F;code&gt;s. Jobs produce goods
or alter a &lt;code&gt;Locality&lt;&#x2F;code&gt;, of which a &lt;code&gt;Region&lt;&#x2F;code&gt; may have many. &lt;code&gt;Regions&lt;&#x2F;code&gt; are fields of &lt;code&gt;Hex&lt;&#x2F;code&gt;es associated with a certain
&lt;code&gt;Scale&lt;&#x2F;code&gt;. Regions exist within a &lt;code&gt;World&lt;&#x2F;code&gt;, and are connected to other regions within a specific hex, and may be contained
within other regions. The connections are arbitrary scale.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1105&quot;&gt;1105&lt;&#x2F;h2&gt;
&lt;p&gt;Another way of approaching this that might be interesting. Hexes are nice for rendering, but representation as a fixed
field is a little limiting. In particular, it would be nice to just think in terms of topology, and then maybe
superimpose some hex system when it’s appropriate?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1231&quot;&gt;1231&lt;&#x2F;h2&gt;
&lt;p&gt;I roughed out some ideas on paper, but rapidly realized I’ll also need some sense of a ‘timeline’ for each party, as
different places within the worlds I manage may move at different rates.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-OCT-2025</title>
        <published>2025-10-26T00:00:00+00:00</published>
        <updated>2025-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/26-oct-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/26-oct-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/26-oct-2025/">&lt;h2 id=&quot;1244&quot;&gt;1244&lt;&#x2F;h2&gt;
&lt;p&gt;I had an idea last night that I think squares everything up. Instead of pulling images in and rendering ‘on-demand’, the
renderer should instead run as an independent process that allows ‘subscribers’&lt;&#x2F;p&gt;
&lt;p&gt;The pipeline would then be for an internal model to update, which the renderer can observe; the renderer creates a new
frame and sends a pointer to each subscriber, the UI is a subscriber. On application start, the model is booted, then
the renderer, then the UI ‘subscribes’ to the renderer and passes the imageref to whatever widgets it likes.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally it’s a queue, so the UI event loop runs, places the new image in the ‘right slot’, but only renders the actual
UI every &lt;code&gt;1&#x2F;f&lt;&#x2F;code&gt; seconds (f = framerate), So if the renderer ends up generating 3 frames before the render call happens,
it should only copy the image for the last of those frames, the rest just being an Arc&#x2F;other ref to the image data. This
also means the renderer can be ‘smart’ in the sense that I can create an SVG of the whole map, and dynamically grab
portions of it after rendering it once. I can also have the renderer manage multiple layers and other tweaks by making
the image reference a little smarter. This nets me the SVG-based approach I wanted (for transportability) and the speed
I’m looking for (since the map should change pretty rarely).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-OCT-2025</title>
        <published>2025-10-20T00:00:00+00:00</published>
        <updated>2025-10-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/20-oct-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/20-oct-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/20-oct-2025/">&lt;h2 id=&quot;1352&quot;&gt;1352&lt;&#x2F;h2&gt;
&lt;p&gt;I don’t know that it fixed it, but it is slightly less laggy now. I need to hook up console or something to get data
out, but I think the issue is that &lt;code&gt;svg&lt;&#x2F;code&gt; is fundamentally going to be slow because it’s just a long, unaccelerated
pipeline and ultimately it’s not even really necessary; I could just work directly on the image buffer.&lt;&#x2F;p&gt;
&lt;p&gt;The upside of svg is that it is lightweight for a render-once-clientside application, which isn’t my intent; and it’s
nice to convert to other image formats and resolutions. The downside is that it is unlikely that I’ll ever be able to
render it quickly enough to ‘work’. I think next step is to start sticking probes around it and seeing if I can get some
timing data out, I suspect it will quickly show more blocking processes that need to be handled; and it will also
probably show that each of those blocking processes still take a long time to render. Low framerates for the thing are
tolerable, but dismal ones won’t be, so I might still go for a ‘render via ratatui-image’ approach, but just manage a
DynamicImage (or some wrapping structure) which I copy out when rendering each frame. Then I can have a process
continually buffer a new frame and just asynchronously ask for the current one each actual rendered frame. Should be
significantly simpler and avoids me having to write a template file.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1425&quot;&gt;1425&lt;&#x2F;h2&gt;
&lt;p&gt;I hooked up tokio_console and found some interesting info. In particular there are, as expected, quite a few blocking
functions. In particular there seem to be 4 copies of the render step running all the time, Only one task seems to ever
actually be running; which shouldn’t be the case, and because of this I seem to remain pretty far down in the queue. I
think tokio is basically shoving blocking tasks onto threads, those tasks take a while to return so it creates another
one w&#x2F;o cancelling the first, and so it quickly exhausts all it’s available worker threads and spins waiting for all
it’s stuff to finish. Trying to feed people in half the time by cooking twice as much food.&lt;&#x2F;p&gt;
&lt;p&gt;It seems that the problem ‘should’ be solved with messages, as I had been moving towards before. Sending a message can
be ignored if the render is already in progress, so you just have a little state machine on the far side and if it’s
rendering, it adds another return address to the queue.&lt;&#x2F;p&gt;
&lt;p&gt;I want to benchmark the actual SVG rendering time for a reasonably complicated SVG, so I think I’m going to create a
separate map renderer that doesn’t do any of the ratatui stuff, then I can figure out a best-possible render time; if
that is acceptable, then I like the idea of trying to keep the SVG-based approach since being able to keep the actual
content of the game in pure xml&#x2F;text seems nice from a longevity point of view. Easy to store and compress, easy to
build another interpreter for, etc. If it’s not, then using &lt;code&gt;image&lt;&#x2F;code&gt; and writing a simple rasterizer (I think that’s the
right term, a thing that takes abstract model of space and turns it into pixels is what I mean, I’m not a graphics guy)
should be the path, since I’ll have all the control I can manage and can make the pipeline async-throughout, which would
hopefully resolve the issue as well. In any case I think it’s a good opportunity to use the &lt;code&gt;state-machine&lt;&#x2F;code&gt; port.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-OCT-2025</title>
        <published>2025-10-10T00:00:00+00:00</published>
        <updated>2025-10-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/10-oct-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/10-oct-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/10-oct-2025/">&lt;h2 id=&quot;0033&quot;&gt;0033&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’ve found the actual issue with the svg rendered, it’s blocking. It needs to run in it’s own thread and the UI
talk to it, separate from &lt;code&gt;tokio&lt;&#x2F;code&gt;, started independently and globally available. &lt;code&gt;tokio&lt;&#x2F;code&gt; can run the UI and provide
requests to the renderer, updating as new frames are available. This &lt;em&gt;may&lt;&#x2F;em&gt; be what &lt;code&gt;spawn_blocking&lt;&#x2F;code&gt; does, I haven’t read
the docs enough to grok it yet. I grepped for it and it’s not in current use anyway, so worth looking through, an old
stackoverflow &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;76965631&#x2F;how-do-i-spawn-possibly-blocking-async-tasks-in-tokio&quot;&gt;here&lt;&#x2F;a&gt;
also points toward it. My initial thought, however, was to either spawn a separate thread with an async channel, then
start tokio, obviating the &lt;code&gt;#[tokio::main]&lt;&#x2F;code&gt; handle and thus DIYing it with this additional thread. The renderer side
would also have to directly manage the Future I think, that seems messy.&lt;&#x2F;p&gt;
&lt;p&gt;I could also just try to implement Future for the svg rendering step itself, so that it’s callable in the async context
directly. I think the implementation would just be a &lt;code&gt;spawn_blocking&lt;&#x2F;code&gt; call.&lt;&#x2F;p&gt;
&lt;p&gt;I may need to grant some access to the tokio runtime to do this?&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;tokio.rs&#x2F;tokio&#x2F;topics&#x2F;bridging#spawning-things-on-a-runtime&lt;&#x2F;p&gt;
&lt;p&gt;Seems relevant.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-AUG-2025</title>
        <published>2025-08-26T00:00:00+00:00</published>
        <updated>2025-08-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/26-aug-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/26-aug-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/26-aug-2025/">&lt;h2 id=&quot;1313&quot;&gt;1313&lt;&#x2F;h2&gt;
&lt;p&gt;I think I need to focus on building a separate svg renderer that does a better job of separating the update&#x2F;render
stuff. The &lt;code&gt;SVG&lt;&#x2F;code&gt; widget should basically first-and-forget the SVG render, and the update should look it up after.
Probably the ‘simplest’ way to do that is to hash the SVG Template after compiling the template, and have the renderer
cache based on that hash. I’d push the &lt;code&gt;template.render()&lt;&#x2F;code&gt; step &lt;em&gt;up&lt;&#x2F;em&gt; to the &lt;code&gt;update&lt;&#x2F;code&gt; call, then on the &lt;code&gt;render&lt;&#x2F;code&gt; call
look up based on the current hash – so that I don’t clone the png data, I just retrieve an ARC to it from the
renderer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1313-1&quot;&gt;1313&lt;&#x2F;h2&gt;
&lt;p&gt;I think I need to focus on building a separate svg renderer that does a better job of separating the update&#x2F;render
stuff. The &lt;code&gt;SVG&lt;&#x2F;code&gt; widget should basically first-and-forget the SVG render, and the update should look it up after.
Probably the ‘simplest’ way to do that is to hash the SVG Template after compiling the template, and have the renderer
cache based on that hash.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>25-AUG-2025</title>
        <published>2025-08-25T00:00:00+00:00</published>
        <updated>2025-08-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/25-aug-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/25-aug-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/25-aug-2025/">&lt;h2 id=&quot;1538&quot;&gt;1538&lt;&#x2F;h2&gt;
&lt;p&gt;Apparently ratatui_image has something for separating rendering, might be able to use that as an example of how to
structure the SVG rendering thread. The current &lt;code&gt;HEAD&lt;&#x2F;code&gt; of ratatui_image has a tokio example as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>21-AUG-2025</title>
        <published>2025-08-21T00:00:00+00:00</published>
        <updated>2025-08-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/21-aug-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/21-aug-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/21-aug-2025/">&lt;h2 id=&quot;0102&quot;&gt;0102&lt;&#x2F;h2&gt;
&lt;p&gt;Still not super happy with the PNG rendering performance, but there is much to do to improve it, and it’s mostly
asynchronous now, all the major issues are worked out with the wiring, just needs a bunch of polish and tests.&lt;&#x2F;p&gt;
&lt;p&gt;I dislike how I’m managing the layout on multiple levels, but it’s the most flexible thing for right now, eventually it
probably makes sense to have it have a fixed initial size so that the render loop can start without a blank screen. I’ve
already hardcoded it to use the &lt;code&gt;kitty&lt;&#x2F;code&gt; protocol to avoid all the &lt;code&gt;picker&lt;&#x2F;code&gt; nonsense that broke input for quite a while.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0924&quot;&gt;0924&lt;&#x2F;h2&gt;
&lt;p&gt;I decided to go to sleep mid thought when I realized what time it was.&lt;&#x2F;p&gt;
&lt;p&gt;The way the layout works right now, it drops everything into a (fresh) hashmap on each call to &lt;code&gt;build_layout&lt;&#x2F;code&gt;, which is
pretty frequent. This means that I’ve got strings littered everywhere. In this form, it’s quite easy to get hard crashes
due to uncatchable typos, which is not ideal. The obvious solution is to use an enum, but that adds some overhead to
re-arranging sections while I work on it, so I think I’m going to tolerate the pain until I’ve firmed up the UI design,
then encode it.&lt;&#x2F;p&gt;
&lt;p&gt;Next step is to chase down the scaling issue, and then work to send the actual png generation as an async task, which I
think should make the UI stay responsive during rendering.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1028&quot;&gt;1028&lt;&#x2F;h2&gt;
&lt;p&gt;I think I need to create an entirely separate thread that communicates over a channel. I’ve been trying to get
&lt;code&gt;tokio::task&lt;&#x2F;code&gt; to work, but I can’t seem to find the right invocation to get it to be non-blocking. Instead I could start
up the &lt;code&gt;App&lt;&#x2F;code&gt; and &lt;code&gt;UI&lt;&#x2F;code&gt; as separate threads that communicate, alternatively, a PNG renderer that runs in a separate
thread, maybe using a shared memory space? Not quite sure how I want to proceed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1145&quot;&gt;1145&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;61752896&#x2F;how-to-create-a-dedicated-threadpool-for-cpu-intensive-work-in-tokio&lt;&#x2F;p&gt;
&lt;p&gt;Seems relevant.&lt;&#x2F;p&gt;
&lt;p&gt;I also need to do some kind of caching&#x2F;don’t re-render if the template hasn’t changed. Probably a simple hash scheme’d
do it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-AUG-2025</title>
        <published>2025-08-18T00:00:00+00:00</published>
        <updated>2025-08-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/18-aug-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/18-aug-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/18-aug-2025/">&lt;h2 id=&quot;0921&quot;&gt;0921&lt;&#x2F;h2&gt;
&lt;p&gt;The process for rendering a hexfield is going to involve the following parts:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Map from image dimensions (which I should look up on load and store in the cache) to nominal hex dimensions, scaling
everything to the same scale. This’ll require some math to determine the anchor points in the SVG for the image&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Figure out the viewbox&#x2F;viewport&#x2F;svg size stuff. This might be just ensuring I’m not working near the SVG origin
(since I think negative x&#x2F;y values are not supported? Not sure. Might be able to solve this by making matching
adjustments to the viewport offset when I select subsections).
- Indeed, my example images have a big pile of surrounding transparency, the hexes are centered, though, so it
should be easy enough to find the center dynamically. which should allow placement relative to the center, it is
absolutely top-left anchored atm (by experimentation).
- This may also explain why the &lt;code&gt;fill&lt;&#x2F;code&gt; wasn’t working, it was, we were just only seeing the transparent section.
I’ll need to experiment to see if adding back the &lt;code&gt;defs&lt;&#x2F;code&gt; saves time once there are a lot of hexes being shown.
- an upshot might be that I could make a &lt;em&gt;texture&lt;&#x2F;em&gt; to apply to the hex, instead of a hex image; contiguous
regions of hexes could pull from coordinated parts of the texture and get semi-random changes to add variety.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Use existing hex math stuff to place all the hexes, this will probably need some more math to go from nominal hexes
in radial space to the image dimensions which will be weird.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Before any of that I &lt;em&gt;have&lt;&#x2F;em&gt; to make this shit async because it is so annoying to wait for the thing. It’d also be good
to get it to automatically rerender every few seconds or whatever.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1024&quot;&gt;1024&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at the async stuff, it may be that I need to separate the drawing side of the &lt;code&gt;SVG&lt;&#x2F;code&gt; stuff and the display. The
widget can have an async ‘update’ function which stores the pngdata in the struct, the render just splats the pngdata to
the screen.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1113&quot;&gt;1113&lt;&#x2F;h2&gt;
&lt;p&gt;I started to tease apart the update&#x2F;render parts of the svg so I can async it. The &lt;code&gt;picker&lt;&#x2F;code&gt; part is a little tricky to
locate, and I’ve got a lot of state that needs managing, but I think I should be able to pass through the picker
information (perhaps as part of the state for SVG?).&lt;&#x2F;p&gt;
&lt;p&gt;It feels like there should be a trait for ‘Async’ widgets (similar to stateful widgets), which are widgets with state
that endure a separate update loop. Each would get all the current layout information, so that, for instance, I can
pre-render the next SVG frame to the correct size, but one would get called to manage FPS and the other for actual state
upate?&lt;&#x2F;p&gt;
&lt;p&gt;IDK, feels like there’s a pattern here, haven’t found it yet.&lt;&#x2F;p&gt;
&lt;p&gt;I definitely think the layout should get cached, maybe I just don’t like immediate-mode UI? :) It’s just a set of rects
that get calculated, it’s another thing that I could stick in an async update loop and reference everywhere.&lt;&#x2F;p&gt;
&lt;p&gt;One crazy idea here would be to refactor so the &lt;em&gt;whole UI&lt;&#x2F;em&gt; is done as an SVG. At that point I’m just sort of streaming
graphics over the terminal protocol so it’s a little bit silly, but I suppose that’s probably what, e.g., canvas is
doing in a browser over HTTP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1319&quot;&gt;1319&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’m moving inexorably towards an event-loop style system with a bunch of asynchronous handlers with a
framerate-managed render loop. The current method does a loop like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. Check for exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. No exit, then handle events (sync)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. Update (async)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. synchronize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5. Draw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What would be ideal is if the startup ran two systems, the frontend UI which just does the &lt;code&gt;draw&lt;&#x2F;code&gt; step on a
fixed-framerate-target loop, and a ‘backend’ component which is asynchronous. The frontend would capture events and send
them to the backend, and request data from the backend when needed to render.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>17-AUG-2025</title>
        <published>2025-08-17T00:00:00+00:00</published>
        <updated>2025-08-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/17-aug-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/17-aug-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/17-aug-2025/">&lt;h2 id=&quot;0130&quot;&gt;0130&lt;&#x2F;h2&gt;
&lt;p&gt;Good progress. I factored out some caches, though the image one isn’t working right just yet. I still need to review the
render function to make sure I got it wired up correctly.&lt;&#x2F;p&gt;
&lt;p&gt;I need to get the UI async for this approach to work. I don’t need particularly high framerates for the map especially
(since it will be mostly static most of the time), and in fact a longer render time for the ‘static’ portion should make
the non-static portion easier to make it’s own, transparent layer that gets dropped on top. Pulling the caches out to be
async also just makes sense, they’re already tossing Arcs around with impugnity.&lt;&#x2F;p&gt;
&lt;p&gt;The image cache is currently caching the whole ImageKind, but I think it should actually cache the tag and data
separately, this would allow me to reconstruct the imagekind at the last minute, avoiding an extra Arc and an unpleasant
&lt;code&gt;.as_ref().clone()&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’m still fighting to get it to fill the polyline hexagon with the image, but practically speaking I can also probably
just use &lt;code&gt;image&lt;&#x2F;code&gt; tags instead, and layer the hexgrid on top of it.&lt;&#x2F;p&gt;
&lt;p&gt;As it is, the process takes about 3s to render the svg as a png, I still can’t actually see the image that’s slowing it
down, but the cache works, I just eat a 3s render time.&lt;&#x2F;p&gt;
&lt;p&gt;Hey, it’s down from the 53 minutes it took on the first run.&lt;&#x2F;p&gt;
&lt;p&gt;It also appears that the use of &lt;code&gt;defs&lt;&#x2F;code&gt; deeply slows the rendering down. So maybe just writing the &lt;code&gt;image&lt;&#x2F;code&gt; directly makes
sense. This is inline with what I want to do with &lt;code&gt;SVGTemplate&lt;&#x2F;code&gt; anyway, so I think that’s the way I’ll go.&lt;&#x2F;p&gt;
&lt;p&gt;I did notice that when working w&#x2F; the webp images, it would frequently miscalculate the size of the grid it should
render. I need to have this derive not from the SVG dimensions, but set the offset based on input values from the
widget, as well as the visible space and ‘zoom’ level of the widget. Some transform exists from the &lt;code&gt;ratatui-image&lt;&#x2F;code&gt;
widget’s &lt;code&gt;Rect&lt;&#x2F;code&gt; and the SVG’s native bounding box based on some scalar zoom level which would map coordinates and
heights and stuff. I’ll need to figure that out and that should resolve the issue. It doesn’t seem to happen with .pngs,
I assume because they are more strict about their bounding box. webp is a mystery to me, all file formats are mysteries,
really.&lt;&#x2F;p&gt;
&lt;p&gt;For now I’ll just use pngs.&lt;&#x2F;p&gt;
&lt;p&gt;using images instead of the polyline does mean that I’ll need to figure out how to convert from where-ever the &lt;code&gt;png&lt;&#x2F;code&gt; is
anchored to the center of the hex it contains. There may be a way to control where the drag point is in SVG, I don’t
know.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1438&quot;&gt;1438&lt;&#x2F;h2&gt;
&lt;p&gt;Definitely a render-box issue, I’ve added a hardcoded 100% rect to the template and it actually should have excluded
some stuff, it appears the width&#x2F;height is controlled by parameters on the &lt;svg&gt; element.
controls what part of a larger document needs to be rendered, so I think that’s also where general camera control logic
ends up.&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;SVG&#x2F;coords.html#TransformProperty&lt;&#x2F;p&gt;
&lt;p&gt;Seems to be useful for this&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>14-AUG-2025</title>
        <published>2025-08-14T00:00:00+00:00</published>
        <updated>2025-08-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/truncheon/14-aug-2025/"/>
        <id>https://disturbed-circles.com/log/truncheon/14-aug-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/truncheon/14-aug-2025/">&lt;h2 id=&quot;1510&quot;&gt;1510&lt;&#x2F;h2&gt;
&lt;p&gt;I got the svg pipeline working, it seems pretty snappy but I’m also not drawing it most of the time. Next step is to
extend the template stuff to allow for drawing shapes and whatnot.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>23-JUL-2025</title>
        <published>2025-07-23T00:00:00+00:00</published>
        <updated>2025-07-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/23-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/23-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/23-jul-2025/">&lt;h2 id=&quot;1305&quot;&gt;1305&lt;&#x2F;h2&gt;
&lt;p&gt;I’m thinking I might want to actually pull all the helm stuff into terraform in &lt;code&gt;earendil&lt;&#x2F;code&gt; – right now I’m using k3s,
but I’d prefer the actual install to be agnostic with respect to k8s host. Instead the k3s install would be barebones,
and just focus on the necessaries to get k3s up and clustered.&lt;&#x2F;p&gt;
&lt;p&gt;Terraform would drive helm, standing up the infrastructure and configuring, e.g., vault and such as well. This would
make it easier to bootstrap vault, as well, and would clarify &lt;code&gt;earendil&lt;&#x2F;code&gt; as all the ‘service’ level automation, and the
rest of &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; for the ‘infrastructure’ level automation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1405&quot;&gt;1405&lt;&#x2F;h2&gt;
&lt;p&gt;Started to move things, need to stop and think through how to organize it. I could have a single helm chart with
subcharts, or move the dependencies up into terraform, not sure how I want to run it just yet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>16-JUL-2025</title>
        <published>2025-07-16T00:00:00+00:00</published>
        <updated>2025-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/16-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/16-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/16-jul-2025/">&lt;h2 id=&quot;1205&quot;&gt;1205&lt;&#x2F;h2&gt;
&lt;p&gt;Trying to use IngressRoute for routing, right now have some draft in &lt;code&gt;earendil&lt;&#x2F;code&gt; that should move back to laurelin since
it’s the ingress for vault; which is laurelin managed, for the moment though it’s handy to keep all the k8s stuff in one
spot. I might wrap it in nix so I can import it via flake.&lt;&#x2F;p&gt;
&lt;p&gt;For the moment I can just leave it in place to work out how that automation will be wired up&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>13-JUL-2025</title>
        <published>2025-07-13T00:00:00+00:00</published>
        <updated>2025-07-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/13-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/13-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/13-jul-2025/">&lt;h2 id=&quot;1048&quot;&gt;1048&lt;&#x2F;h2&gt;
&lt;p&gt;I split off &lt;code&gt;earendil&lt;&#x2F;code&gt; for housing helm charts, it presently has nothing in it. I’ll store instructions on setup there
as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>12-JUL-2025</title>
        <published>2025-07-12T00:00:00+00:00</published>
        <updated>2025-07-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/12-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/12-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/12-jul-2025/">&lt;h2 id=&quot;1456&quot;&gt;1456&lt;&#x2F;h2&gt;
&lt;p&gt;I set up a vault auto-chart, and will set up a vault-operator autochart, but I need to figure out how I’m storing all my
helm charts first, I don’t like where they live now (in telperion south of the emerald.city VM folder), since they
should be relatively agnostic.&lt;&#x2F;p&gt;
&lt;p&gt;I could store them in laurelin, but they aren’t going to be nix files so they are a little out of place.&lt;&#x2F;p&gt;
&lt;p&gt;I could store them in a new repo, and tbh that’s where I’m leaning, but it means if I need a secrets-repo for it I’ve
added another narya, which I’d like to keep to a minimum.&lt;&#x2F;p&gt;
&lt;p&gt;I think they’re probably going to get split into their own repo, my plan is to largely have the &lt;code&gt;k3s&lt;&#x2F;code&gt; module in laurelin
set up the initial state that the repo would expect, and then the repo will contain an ‘initialize’ script that runs
through all the bootstrapping, and the rest will just be ‘normal’ helm-files with a parent ‘install&#x2F;upgrade’ script.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I suspect I’ll build an operator for all my stuff, but today is not that day.&lt;&#x2F;p&gt;
&lt;p&gt;An alternative would be to have some of the bootstrap script contained in the module itself, since I’m going to have it
minimally be able to set up:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Vault&lt;&#x2F;li&gt;
&lt;li&gt;Cert-manager&lt;&#x2F;li&gt;
&lt;li&gt;NFS&lt;&#x2F;li&gt;
&lt;li&gt;Longhorn&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Then it could drop a bunch of systemd oneshots that depend on a parent job that does the initial install
semi-automatically. You’d deploy a single node in ‘server’ mode, log in, run the script via &lt;code&gt;systemctl start emerald-city-k8s-install&lt;&#x2F;code&gt; or whatever, then it’d spit back the secret you need for all the other client machines.&lt;&#x2F;p&gt;
&lt;p&gt;The other chart repo would then just contain install files for the services on top of the substrate.&lt;&#x2F;p&gt;
&lt;p&gt;Right now I’m also using an ‘out of band’ docker registry, so it’d probably be good to add an option to run said
registry and automatically generate the relevant trust files; the true ideal would be to run it &lt;em&gt;within k8s&lt;&#x2F;em&gt; and have it
loop back, though I suspect that might be not recommended, because cool things rarely are.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>9-JUL-2025</title>
        <published>2025-07-09T00:00:00+00:00</published>
        <updated>2025-07-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/9-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/9-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/9-jul-2025/">&lt;h2 id=&quot;0044&quot;&gt;0044&lt;&#x2F;h2&gt;
&lt;p&gt;I’m making a distinction – most of what I want to run on the k3s cluster is going to be ‘ephemeral’, in the sense that
I don’t necessarily know what I want to run and am going to iterate on it reasonably quickly, and don’t want to have to
version it against the &lt;em&gt;server’s&lt;&#x2F;em&gt; configuration. However, some items are required-on-first-run, e.g., setting up storage
drivers, GPU passthrough where it’s appropriate, etc.&lt;&#x2F;p&gt;
&lt;p&gt;I’m writing my own charts mostly for the practice for all the ephemeral stuff, but for the more ‘structural’ stuff, that
will be encoded into the module itself.&lt;&#x2F;p&gt;
&lt;p&gt;NFS and Longhorn both should get set up, nfs should be easy to get running with nancy which will unblock my foundry
chart progress.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>8-JUL-2025</title>
        <published>2025-07-08T00:00:00+00:00</published>
        <updated>2025-07-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/8-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/8-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/8-jul-2025/">&lt;h2 id=&quot;1045&quot;&gt;1045&lt;&#x2F;h2&gt;
&lt;p&gt;Got ody-01 fixed, needed to fully delete the k3s stuff by following:
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;blob&#x2F;master&#x2F;pkgs&#x2F;applications&#x2F;networking&#x2F;cluster&#x2F;k3s&#x2F;docs&#x2F;CLUSTER_UPKEEP.md&quot;&gt;this&lt;&#x2F;a&gt; doc
to clear everything; this is likely down to the way I built the machines having a pile of crap left on them.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to build a ‘mode’ option into the service that will add an option to set the service to ‘clean’ mode which
should rip out all the relevant stuff – or maybe just a script, idk.&lt;&#x2F;p&gt;
&lt;p&gt;Next step is to get helm setup.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>7-JUL-2025</title>
        <published>2025-07-07T00:00:00+00:00</published>
        <updated>2025-07-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/7-jul-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/7-jul-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/7-jul-2025/">&lt;h2 id=&quot;2131&quot;&gt;2131&lt;&#x2F;h2&gt;
&lt;p&gt;I’m planning to move minas-tarwon &amp;amp; co to &lt;code&gt;dragon&lt;&#x2F;code&gt;, which should improve average build times. Archi is going to be an AV
machine after that, to help support some efforts for &lt;code&gt;infinite-dungeon&lt;&#x2F;code&gt;, which has driven most of the recent changes
here and occupies a good portion of my time.&lt;&#x2F;p&gt;
&lt;p&gt;I’m also working on setting up the k3s environment on &lt;code&gt;ody&lt;&#x2F;code&gt;&amp;amp;co, the intent is that my various RPis and SFF machines will
be dragooned into helping with the workloads eventually, but building out the modules in &lt;code&gt;laurelin&lt;&#x2F;code&gt; will be easier with
some VMs that are easy to blow away and reset.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-JUN-2025</title>
        <published>2025-06-19T00:00:00+00:00</published>
        <updated>2025-06-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/19-jun-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/19-jun-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/19-jun-2025/">&lt;h2 id=&quot;1814&quot;&gt;1814&lt;&#x2F;h2&gt;
&lt;p&gt;Got &lt;code&gt;affine&lt;&#x2F;code&gt; set up on &lt;code&gt;barge&lt;&#x2F;code&gt;, began to look into reconfiguring my cloudflare tunnel to point into barge, probably
easiest to expose it on the host itself, and then configure it in nixos.&lt;&#x2F;p&gt;
&lt;p&gt;I still want to migrate all this stuff to k8s, as well, but for the moment it’s just simpler to drop it all here. I need
to get foundry stood up there as well, which I suspect will be comparatively simpler.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to extend the container definition to accept an arbitrary RP domain, since the incoming traffic over the
tunnel should only go to a few services. Would prefer k8s namespacing, but the plan is to turn the thing off&#x2F;allowlist
IPs, so should be alright.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, things are proceeding apace.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>14-JUN-2025</title>
        <published>2025-06-14T00:00:00+00:00</published>
        <updated>2025-06-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/14-jun-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/14-jun-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/14-jun-2025/">&lt;h2 id=&quot;1609&quot;&gt;1609&lt;&#x2F;h2&gt;
&lt;p&gt;I did some refactoring and ended up with 3 identical VMs for the k3s cluster, all running on BTG right now, but once
I’ve got it working I can migrate to multiple machines. I’m still using the current VM model, I plan to test the
build-a-vm-directly on DOP for ease, and then figure out how to share it everywhere after the fact.&lt;&#x2F;p&gt;
&lt;p&gt;Next step is to stand up the k3s cluster and do any adjustments to horsepower needed. Then I can migrate services over
to be managed by some helm charts and glue.&lt;&#x2F;p&gt;
&lt;p&gt;That should let me retire barge, and I should be able to retire daktylos as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-MAY-2025</title>
        <published>2025-05-18T00:00:00+00:00</published>
        <updated>2025-05-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/18-may-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/18-may-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/18-may-2025/">&lt;h2 id=&quot;1140&quot;&gt;1140&lt;&#x2F;h2&gt;
&lt;p&gt;I swear I didn’t plan to start this 23h59m after the last one, I just got distracted and managed to land on it.&lt;&#x2F;p&gt;
&lt;p&gt;So – doing a bit of reading, I think I should be able to start by standing up 3 copies of &lt;code&gt;odysseus&lt;&#x2F;code&gt; (mod a rename) and
get something wired together, from there I can just run an ‘all-leader’ cluster and probably do just fine. Eventually
I’ll spread those managers to &lt;code&gt;toto&lt;&#x2F;code&gt;, &lt;code&gt;maiasaura&lt;&#x2F;code&gt;, and the other small machines I have scattered, and just run workers
on BTG, DOP, and Nancy (if I decide to rebuild her as a nixos machine, anyway, I don’t plan to fight it if setting up a
k3s worker there is hard; maybe synology has a package for it but w&#x2F;e). I can definitely use the iscsi&#x2F;nfs storage
drivers at least, but it’d be cool to run some work directly on the nancy machine where it will be colocated w&#x2F; the data
it needs and could ostensibly use local-file storage drivers.&lt;&#x2F;p&gt;
&lt;p&gt;One issue I need to work out not that I’m not going to netboot things is how to build whole a new VM quickly and ideally
without too much manual work. Right now the process is:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Create a disk in BTG’s config&lt;&#x2F;li&gt;
&lt;li&gt;Create a VM definition that mounts that disk, sets cpu&#x2F;mem&#x2F;etc params&lt;&#x2F;li&gt;
&lt;li&gt;Attach the install ISO in that VM def as boot order 1&lt;&#x2F;li&gt;
&lt;li&gt;Deploy BTG (sometimes provoking a network failure because of the weird bonding situation I have set up)&lt;&#x2F;li&gt;
&lt;li&gt;SSH to the new VM on whatever address it grabbed from DHCP, install a base that includes my user, basic nix config,
etc.&lt;&#x2F;li&gt;
&lt;li&gt;After install is done, down the machine, update the vm definition to not boot the install iso&lt;&#x2F;li&gt;
&lt;li&gt;Update BTG again with the new def.&lt;&#x2F;li&gt;
&lt;li&gt;Boot the new VM&lt;&#x2F;li&gt;
&lt;li&gt;Apply it’s final config via the &lt;code&gt;boot&lt;&#x2F;code&gt; option&lt;&#x2F;li&gt;
&lt;li&gt;Reboot the machine to it’s final config.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is quite tedious, and also relies on having the data stored right on disk on BTG, no option for offering disks from
a remote source (e.g., iSCSI). It also involves a deploy to either BTG (#4, 7) or the VM (#5, 9) a total of four times.&lt;&#x2F;p&gt;
&lt;p&gt;I can solve some of this with UEFI bouncing, I think, I can build the whole image as a UEFI partitioned image and then
EFI bounce like I am with Barge. This costs at boot time, but only a little, and it cuts out several steps.&lt;&#x2F;p&gt;
&lt;p&gt;Even better, I think &lt;code&gt;nixos-generators&lt;&#x2F;code&gt; will basically do this for me.&lt;&#x2F;p&gt;
&lt;p&gt;Next, if I can get iSCSI cooking, then I can build this into a remote-root&#x2F;local-scratch setup, where there is a iSCSI
based root system that is fairly minimal, and then overlay a local disk (or another iSCSI) as an overlayfs which will
get subsequent updates to that machine. I think the procedure would then just be:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Build a nix definition for a specific VM&lt;&#x2F;li&gt;
&lt;li&gt;Build a UEFI-bootable image to an iSCSI target
&lt;ul&gt;
&lt;li&gt;In this mode, the image should not try to boot a second overlay drive from the next step&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Create a second iSCSI target drive&lt;&#x2F;li&gt;
&lt;li&gt;Build a libvirt definition that mounts both the #2 image and the #3 disk as an overlay&lt;&#x2F;li&gt;
&lt;li&gt;Update BTG to run the new VM.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This still requires running an update against the whole hypervisor, but it’s a hell of a lot simpler than my current
methodology. I can start by building up a &lt;code&gt;pinky&lt;&#x2F;code&gt; image with this model, hosting the iSCSI on Nancy as I already have
some test disks set up over there.&lt;&#x2F;p&gt;
&lt;p&gt;Another option is to use nixosgenerators and drop the whole VM image as a qemu image. This may be much easier but does
mean rsyncing around the VM image.&lt;&#x2F;p&gt;
&lt;p&gt;Practically it would also mean I’d want to probably tag images with some relevant sha of the repo they were built from,
not sure how I want to do that yet though. This could also still use the above EFI bounce approach, every vm definition
would just load rEFInd and point to the underlying thing. There is an option to install a bootloader as well, or
netboot, so worth exploring on pinky for sure I think.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>17-MAY-2025</title>
        <published>2025-05-17T00:00:00+00:00</published>
        <updated>2025-05-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/17-may-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/17-may-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/17-may-2025/">&lt;h2 id=&quot;1141&quot;&gt;1141&lt;&#x2F;h2&gt;
&lt;p&gt;It’s all fixed, basically.&lt;&#x2F;p&gt;
&lt;p&gt;I switched to a proper SSD based install on BTG by swapping the Optical Drive for an SSD. I have a UEFI based install
there because initially I was planning to just EFI bounce via &lt;code&gt;rEFInd&lt;&#x2F;code&gt;, but it turned out not to be necessary.&lt;&#x2F;p&gt;
&lt;p&gt;Now I need to get DOP set up the same way, get the GPU installed there as well, and then get to work bringning up a k3s
cluster up and running.&lt;&#x2F;p&gt;
&lt;p&gt;This also meant I removed the netbooting infrastructure from the VMs as well, which means I need to convert the other
services over to a proper install based system, or have everything like, boot to refind, which is what &lt;code&gt;barge&lt;&#x2F;code&gt; is doing
right now.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’ll probably just start with three VMs on the same host with a single worker, that should be enough to get
everything set up, I can migrate services over, and then I can work on migrating to a more resilient distribution of
workers and leaders.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>30-APR-2025</title>
        <published>2025-04-30T00:00:00+00:00</published>
        <updated>2025-04-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/30-apr-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/30-apr-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/30-apr-2025/">&lt;h2 id=&quot;0051&quot;&gt;0051&lt;&#x2F;h2&gt;
&lt;p&gt;I’ven’t made any progress on the above, and have justified what may otherwise be described as laziness as an impromptu
experiment in seeing how long it takes bitrot or force majeure to break something; turns out the latter won. Some work
on the powerlines down the street yeilded a brownout, which tripped my NAS into a strange state which required some
effort to recover. This left the netboot image mounts in a state of corruption, it appears, and my main VM host also
felt the sting, leading to a situation where all my VMs aren’t available.&lt;&#x2F;p&gt;
&lt;p&gt;This was at least somewhat expected, partly because even though I have a rackmount UPS for the servers I haven’t
installed it because it requires also installing some electrical and I simply haven’t had the gumption. In any case, the
unfortunate situation is that the netboot apparatus to generate &lt;em&gt;new&lt;&#x2F;em&gt; images is &lt;em&gt;also&lt;&#x2F;em&gt; broken, so I need to either fix
what’s there or convert to something new, neither of which are super exciting, but at least the latter means I’ll have
some time to play with iSCSI, which appeals to me as a potentially interesting alternative to the &lt;code&gt;NFS&lt;&#x2F;code&gt; route I had
planned. There is also &lt;code&gt;tvix&lt;&#x2F;code&gt; to consider.&lt;&#x2F;p&gt;
&lt;p&gt;At the moment, the state is that BTG and DOP both can’t boot up; but everything else is running alright. Rewriting the
netboot to avoid the image size issue will also make netboot-everything viable again, which will be nice for automating
VM creation, which in turn should make moving services to k8s much simpler.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1238&quot;&gt;1238&lt;&#x2F;h2&gt;
&lt;p&gt;What was originally a small issue has grown. In attempting to untangle things, I needed to get my laptop, Archimedes,
updated and working, however he is now crashing on &lt;em&gt;update&lt;&#x2F;em&gt;, which is a new thing for me in Nix world. I think he might
just need a bit of cleaning, but I’m getting all my stuff committed and pushed before continuing.&lt;&#x2F;p&gt;
&lt;p&gt;The fun never really stops.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1-APR-2025</title>
        <published>2025-04-01T00:00:00+00:00</published>
        <updated>2025-04-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/1-apr-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/1-apr-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/1-apr-2025/">&lt;h2 id=&quot;0031-spring-cleaning-1&quot;&gt;0031 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Tag audit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Complete ticket making from audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Add additional tasks to P2 from audit (if any)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Merge P1&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Phase 2
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Cache Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Variation Refactor to use Spell + Tape-&amp;gt;Spell rename&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Better CI Pipeline&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Test Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Fastchess UCI test&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Benchmark harness&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I’m gonna make a pile of issues because I don’t really want to work on this stuff necessarily right now, but I knew
there were only a few logical issues in all the tags that I just kept running into, so I wanted to gather them up.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t love making issues, it feels uncomfortably organized and rational, and I strive to avoid any appearance of
rationality.&lt;&#x2F;p&gt;
&lt;p&gt;It is a good opportunity to play with a new vim plugin though, so I suppose that will have to sustain me through my
discomfort.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1003-spring-cleaning-1&quot;&gt;1003 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Tag audit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Complete ticket making from audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Add additional tasks to P2 from audit (if any)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Merge P1&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Phase 2
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Cache Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Variation Refactor to use Spell + Tape-&amp;gt;Spell rename&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Better CI Pipeline&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Test Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Fastchess UCI test&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Benchmark harness&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Just need to merge, then start a new branch. I didn’t see any tickets that &lt;em&gt;need&lt;&#x2F;em&gt; to be done in P2. I need to go through
one last time and remove all the things I said I’d remove, and then I should be ready to merge.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1025-spring-cleaning-1&quot;&gt;1025 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Tag audit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Complete ticket making from audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Add additional tasks to P2 from audit (if any)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Merge P1&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Phase 2
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Cache Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Variation Refactor to use Spell + Tape-&amp;gt;Spell rename&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Better CI Pipeline&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Test Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Fastchess UCI test&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Benchmark harness&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Phase 1 complete, now onto the real refactoring tasks. I’m going to start with Spell&#x2F;Variation, as I think it’s probably
the longest pole of the bunch and will close two tickets if I’m efficient.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>31-MAR-2025</title>
        <published>2025-03-31T00:00:00+00:00</published>
        <updated>2025-03-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/31-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/31-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/31-mar-2025/">&lt;h2 id=&quot;0002-spring-cleaning-1&quot;&gt;0002 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;Cache needs to be refactored to a generic key, ultimately this will be a LRU cache with a generic key type.&lt;&#x2F;li&gt;
&lt;li&gt;Spell needs to have Familiar refactored to rely on a SpellState trait&lt;&#x2F;li&gt;
&lt;li&gt;Tape needs to be renamed to Spell&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;BEN&lt;&#x2F;code&gt; -&amp;gt; -basic
&lt;ul&gt;
&lt;li&gt;This means figuring out the &lt;code&gt;to_fen_position&lt;&#x2F;code&gt; extension, which might be able to stay put? IDK. In theory
that means this can just be moved over and no api change, since query is already over there.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;FIXMEs, TODOs, and the like need an audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Reorganize directory structure&lt;&#x2F;li&gt;
&lt;li&gt;Rename -core to -representation&lt;&#x2F;li&gt;
&lt;li&gt;rename -basic to -core&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Get all the tests uncommented (in place) and passing.
&lt;ul&gt;
&lt;li&gt;With caveats, there are still some tests pending a refactor, but I think I got everything that could be easily
re-enabled.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;nix run #ci&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
-parser extraction&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I think I might go ahead and merge this after a few final checks, and start &lt;code&gt;spring-cleaning-2&lt;&#x2F;code&gt;, maybe after the
renames? In -core (right now), there is still:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;types&#x2F;log  # Goes away with the Familiar&#x2F;Variation rewrite.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;coup&#x2F;rep # should be renamed to `coup` and be a top level module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;game&#x2F;* # needs heavy refactoring to use the new familiar system&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;interface&#x2F; # probably can just live in `game`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That should simplify it a lot and I think I’m done reorganizing after that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0052-spring-cleaning-1&quot;&gt;0052 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;I went ahead and got &lt;code&gt;fastchess&lt;&#x2F;code&gt; installed via a derivation in &lt;code&gt;nix&#x2F;fastchess.nix&lt;&#x2F;code&gt;. This’ll build on the first entry,
which sucks a bit, but maybe I can delay that later by hiding the &lt;code&gt;fastchess&lt;&#x2F;code&gt; acceptance tests working behind a flake
app or something.&lt;&#x2F;p&gt;
&lt;p&gt;Speaking of, the main purpose for &lt;code&gt;fastchess&lt;&#x2F;code&gt; is going to be the &lt;code&gt;UCI&lt;&#x2F;code&gt; compliance tool that just came out, that’ll help
a lot with getting the engine working correctly and saves me a ton of time trying to decipher what the semantics should
be, I can just focus on getting the suite to pass.&lt;&#x2F;p&gt;
&lt;p&gt;That’s enough for one day though, the rest of the renaming tomorrow I think, then on to refactoring.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1005-spring-cleaning-1&quot;&gt;1005 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        FAIL [   0.017s] hazel-test::zobrist zobrist::zobrist_update_is_idempotent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;──── STDOUT:             hazel-test::zobrist zobrist::zobrist_update_is_idempotent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;running 1 test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test zobrist::zobrist_update_is_idempotent ... FAILED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;failures:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;failures:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    zobrist::zobrist_update_is_idempotent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.00s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;──── STDERR:             hazel-test::zobrist zobrist::zobrist_update_is_idempotent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[tests&#x2F;zobrist_test.rs:126:13] z1 = Z|0x0000000000000000|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[tests&#x2F;zobrist_test.rs:126:13] z2 = Z|0x0000000000000000|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;thread &amp;#39;zobrist::zobrist_update_is_idempotent&amp;#39; panicked at &#x2F;home&#x2F;jfredett&#x2F;.cargo&#x2F;registry&#x2F;src&#x2F;index.crates.io-1949cf8c6b5b557f&#x2F;quickcheck-1.0.3&#x2F;src&#x2F;tester.rs:165:28:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[quickcheck] TEST FAILED. Arguments: (Assert &amp;lt;b Kk - 8 55390&amp;gt;, Assert &amp;lt;b Kk - 8 31393&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is an interesting failure, look at those metadata asserts resulting in a null. Very interesting. It is not
particularly common, I assume this is a natural collision, and I’m mostly curious about what components of the thing
it’s sensitive too. This test is pretty simple, it takes two random alterations and then calculates:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;z1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; z1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; z2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; z2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verifying that the zobrist self-inverts, basically. I only log the values out, not the alterations, so I’ve changed
that, but since the test is flaky, it’s hard to reproduce, so I added additional logging and hopefully I’ll catch one
before too long.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1514-spring-cleaning-1&quot;&gt;1514 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;Cache needs to be refactored to a generic key, ultimately this will be a LRU cache with a generic key type.&lt;&#x2F;li&gt;
&lt;li&gt;Spell needs to have Familiar refactored to rely on a SpellState trait&lt;&#x2F;li&gt;
&lt;li&gt;Tape needs to be renamed to Spell&lt;&#x2F;li&gt;
&lt;li&gt;FIXMEs, TODOs, and the like need an audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;BEN&lt;&#x2F;code&gt; -&amp;gt; -basic
&lt;ul&gt;
&lt;li&gt;This means figuring out the &lt;code&gt;to_fen_position&lt;&#x2F;code&gt; extension, which might be able to stay put? IDK. In theory
that means this can just be moved over and no api change, since query is already over there.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Reorganize directory structure&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Rename -core to -representation&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
rename -basic to -core&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Get all the tests uncommented (in place) and passing.
&lt;ul&gt;
&lt;li&gt;With caveats, there are still some tests pending a refactor, but I think I got everything that could be easily
re-enabled.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
nix run #ci&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
-parser extraction&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I’m gonna rewrite my TODO list now in terms of phase 2.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Tag audit&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Phase 2
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Cache Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Variation Refactor to use Spell + Tape-&amp;gt;Spell rename&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Better CI Pipeline&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Test Refactor&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Fastchess UCI test&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
Benchmark harness&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I’ll probably split &lt;em&gt;some&lt;&#x2F;em&gt; of that out to a phase 3, but I don’t know what yet. The UCI test from &lt;code&gt;fastchess&lt;&#x2F;code&gt; is a real
windfall, so I definitely want to get that going quickly, but it’s probably the most ‘phase-3’-y of the bunch. The list
is in rough order, but I rarely work in order.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>30-MAR-2025</title>
        <published>2025-03-30T00:00:00+00:00</published>
        <updated>2025-03-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/30-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/30-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/30-mar-2025/">&lt;h2 id=&quot;1514-spring-cleaning-1&quot;&gt;1514 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;I pulled out the integration test, and right now I think I’m just going to focus on moving tests into their own modules
where it makes sense. Eventually most tests will not be co-located with the code-under-test, as I talked about before. I
haven’t brought in any new frameworks just yet, as I’m still determining what the best approach is going to be.&lt;&#x2F;p&gt;
&lt;p&gt;Now that I’ve got everything else pulled out though, I think it’s time to return to extracting the &lt;code&gt;parser&lt;&#x2F;code&gt; stuff, at
which point I think &lt;code&gt;-core&lt;&#x2F;code&gt; is sufficiently gutted so as to be ready for the great renaming.&lt;&#x2F;p&gt;
&lt;p&gt;I’m leaving the unused dependencies in place for the test crate for now, I suspect it’ll be worthwhile to reduce it at
some point.&lt;&#x2F;p&gt;
&lt;p&gt;The only other item I need to actually &lt;em&gt;add&lt;&#x2F;em&gt; to the list above is “10. move to a &lt;code&gt;nix run #ci&lt;&#x2F;code&gt; like &lt;code&gt;tabitha&lt;&#x2F;code&gt; has”, I
think that should greatly simplify my CI pipeline and make it easier to add in lints and git hooks and stuff later.&lt;&#x2F;p&gt;
&lt;p&gt;So the current TODO list is:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Cache needs to be refactored to a generic key, ultimately this will be a LRU cache with a generic key type.&lt;&#x2F;li&gt;
&lt;li&gt;Spell needs to have Familiar refactored to rely on a SpellState trait&lt;&#x2F;li&gt;
&lt;li&gt;Tape needs to be renamed to Spell&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;BEN&lt;&#x2F;code&gt; -&amp;gt; -basic
&lt;ul&gt;
&lt;li&gt;This means figuring out the &lt;code&gt;to_fen_position&lt;&#x2F;code&gt; extension, which might be able to stay put? IDK. In theory
that means this can just be moved over and no api change, since query is already over there.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;FIXMEs, TODOs, and the like need an audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Reorganize directory structure&lt;&#x2F;li&gt;
&lt;li&gt;Rename -core to -representation&lt;&#x2F;li&gt;
&lt;li&gt;rename -basic to -core&lt;&#x2F;li&gt;
&lt;li&gt;Get all the tests uncommented (in place) and passing.&lt;&#x2F;li&gt;
&lt;li&gt;nix run #ci&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I think #9 is the next port of call, I can use it as an opportunity to move some tests around as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1536-spring-cleaning-1&quot;&gt;1536 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;One of the things I need to sit and think about is the way I convert between representations.&lt;&#x2F;p&gt;
&lt;p&gt;I was reading a bit about the &lt;code&gt;fearless-simd&lt;&#x2F;code&gt; project. It uses ZSTs as ‘tokens’ representing the &lt;em&gt;capability&lt;&#x2F;em&gt; of SIMD
independent of the &lt;em&gt;implementation&lt;&#x2F;em&gt; of SIMD, in a relatively ‘low cost’ sort of way to encode the &lt;em&gt;intent&lt;&#x2F;em&gt; into the type
system and then use it to determine an optimal implementation using whatever SIMD primitives are locally available. I
think I’d like to try something similar at some point for my representations. A recurring frustration is the need to
pick &lt;em&gt;a&lt;&#x2F;em&gt; representation as ‘canonical’ when no such representation really deserves that title. Bitboards are useful
sometimes, rank-file tuples others, strings others, it’s not natural to pick any one. There is no good type to give the
raw number or tuple-of-numbers that doesn’t include generally unnecessary bound checking. Bitboards are fine for what
they can do but quite limited in other ways, same with strings. Ideally I should be able to pick whatever representation
is ‘best’ for the current situation, leaving the others behind, but I don’t know what the ‘best’ rep is ahead of time.&lt;&#x2F;p&gt;
&lt;p&gt;To square this (hah), I rely on &lt;code&gt;impl Into&amp;lt;Square&amp;gt;&lt;&#x2F;code&gt; frequently, but htis is also a representation with a downside. It
says, “I &lt;em&gt;can become&lt;&#x2F;em&gt; a &lt;em&gt;specific&lt;&#x2F;em&gt; known implemnetation, but you will have to pay at least the &lt;code&gt;.into()&lt;&#x2F;code&gt; cost and maybe
a second to convert it to the ‘real’ type you want.” I can justfy paying &lt;em&gt;something&lt;&#x2F;em&gt;, but I hate paying it twice.&lt;&#x2F;p&gt;
&lt;p&gt;Relying on &lt;code&gt;From&#x2F;Into&lt;&#x2F;code&gt; also leads to a lot of weird situations where I can’t rely on type inference to ‘do the right
thing’ and guess the type correctly, leaving me to add annotations inconveniently.&lt;&#x2F;p&gt;
&lt;p&gt;If I instead had something like &lt;code&gt;Square&lt;&#x2F;code&gt; as a collection of ZSTs, each with &lt;em&gt;constant&lt;&#x2F;em&gt; implementations of what are now
&lt;code&gt;From&#x2F;Into&lt;&#x2F;code&gt;s, I could have an API like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;#[&lt;&#x2F;span&gt;&lt;span&gt;quickcheck&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;    A1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;bitboard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;is_set&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;((&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;A1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rank&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; A1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()))&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which isn’t too bad, and it means that the actual type I’m passing around is a finite type family, something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; This presumes I can const-trait...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;trait&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; bitboard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Bitboard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; rank&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; A1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt; for&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; A1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There aren’t too many representations to target, but I could do similar things with &lt;code&gt;Piece&lt;&#x2F;code&gt;, &lt;code&gt;Color&lt;&#x2F;code&gt;, etc where it was
needed. Essentially this is the same thing as how I tend to rely on &lt;code&gt;Query&lt;&#x2F;code&gt;, but where &lt;code&gt;Query&lt;&#x2F;code&gt; is really an open
specification with a potentially unbounded number of implementors, &lt;code&gt;Square&lt;&#x2F;code&gt; is &lt;em&gt;really&lt;&#x2F;em&gt; finite and basically will never
be extended.&lt;&#x2F;p&gt;
&lt;p&gt;Something to chew on, anyway.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1620-nice-spring-cleaning-1&quot;&gt;1620 (nice) - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;Cache needs to be refactored to a generic key, ultimately this will be a LRU cache with a generic key type.&lt;&#x2F;li&gt;
&lt;li&gt;Spell needs to have Familiar refactored to rely on a SpellState trait&lt;&#x2F;li&gt;
&lt;li&gt;Tape needs to be renamed to Spell&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;BEN&lt;&#x2F;code&gt; -&amp;gt; -basic
&lt;ul&gt;
&lt;li&gt;This means figuring out the &lt;code&gt;to_fen_position&lt;&#x2F;code&gt; extension, which might be able to stay put? IDK. In theory
that means this can just be moved over and no api change, since query is already over there.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;FIXMEs, TODOs, and the like need an audit.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Reorganize directory structure&lt;&#x2F;li&gt;
&lt;li&gt;Rename -core to -representation&lt;&#x2F;li&gt;
&lt;li&gt;rename -basic to -core&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Get all the tests uncommented (in place) and passing.
&lt;ul&gt;
&lt;li&gt;With caveats, there are still some tests pending a refactor, but I think I got everything that could be easily
re-enabled.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;nix run #ci&lt;&#x2F;li&gt;
&lt;li&gt;-parser extraction&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>29-MAR-2025</title>
        <published>2025-03-29T00:00:00+00:00</published>
        <updated>2025-03-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/29-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/29-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/29-mar-2025/">&lt;h2 id=&quot;0730-spring-cleaning-1&quot;&gt;0730 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;First things first, pretty sure I had dates wrong for previous log entries, so I adjusted.&lt;&#x2F;p&gt;
&lt;p&gt;Second, I’m working on extracting &lt;code&gt;spell&lt;&#x2F;code&gt;, but it’s more complicated because of the way I was managing specific state
update stuff, basically because I’m not using an interface for state objects. In particular I have a number of impls for
Familiar’s which fix a particular generic parameter, which I can’t do outside of the home crate; this is a good thing
ultimately, but will make extraction harder.&lt;&#x2F;p&gt;
&lt;p&gt;For now, I’m just cranking away at what errors I can resolve, and then once I’ve reduced to the minimum, I’ll figure out
how to sort things.&lt;&#x2F;p&gt;
&lt;p&gt;I also need to refactor the old Variation-specific familiar and really Variation itself to a &lt;code&gt;Tape&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;Spell&lt;&#x2F;code&gt; based
system, but I want to get the crate extracted and the name change performed first.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1001-spring-cleaning-1&quot;&gt;1001 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;Couple remaining open refactoring jobs now:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Cache needs to be refactored to a generic key, ultimately this will be a LRU cache with a generic key type.&lt;&#x2F;li&gt;
&lt;li&gt;Spell needs to have Familiar refactored to rely on a trait&lt;&#x2F;li&gt;
&lt;li&gt;Tape needs to be renamed to Spell&lt;&#x2F;li&gt;
&lt;li&gt;Move &lt;code&gt;BEN&lt;&#x2F;code&gt; -&amp;gt; -basic
&lt;ul&gt;
&lt;li&gt;This means figuring out the &lt;code&gt;to_fen_position&lt;&#x2F;code&gt; extension, which might be able to stay put? IDK. In theory
that means this can just be moved over and no api change, since query is already over there.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;FIXMEs, TODOs, and the like need an audit.&lt;&#x2F;li&gt;
&lt;li&gt;Reorganize directory structure&lt;&#x2F;li&gt;
&lt;li&gt;Rename -core to -representation&lt;&#x2F;li&gt;
&lt;li&gt;rename -basic to -core&lt;&#x2F;li&gt;
&lt;li&gt;Get all the tests uncommented (in place) and passing.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Once all these are done (and I just want to audit tags for now, not necessarily do anything to resolve them unless it’s
very easy), I can get started on the test refactoring, which’ll be spring-cleaning-2, I think.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1517-spring-cleaning-1&quot;&gt;1517 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;Finished extracting &lt;code&gt;spell&lt;&#x2F;code&gt; and moving &lt;code&gt;ben&lt;&#x2F;code&gt; to &lt;code&gt;-basic&lt;&#x2F;code&gt;. Dependencies are already minimized, and I can see the end
approaching. This ticks off #4 from above.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1527-spring-cleaning-1&quot;&gt;1527 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;Reorganized the crates a bit, deeper directory structure but cleaner lines. Finishes #6 above.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>28-MAR-2025</title>
        <published>2025-03-28T00:00:00+00:00</published>
        <updated>2025-03-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/28-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/28-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/28-mar-2025/">&lt;h2 id=&quot;1002-spring-cleaning-1&quot;&gt;1002 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;Got &lt;code&gt;-engine&lt;&#x2F;code&gt; pulled out, started pulling on &lt;code&gt;-generator&lt;&#x2F;code&gt;, and found that it tangles a bit into the &lt;code&gt;Cache&#x2F;ATM&lt;&#x2F;code&gt; thing,
which can be extracted, but tangles (due to a shortcut) to the &lt;code&gt;Zobrist&lt;&#x2F;code&gt; type, and so I’m left with the question of
‘where should &lt;code&gt;Zobrist&lt;&#x2F;code&gt; go?’ Zobrist currently depends on both &lt;code&gt;hazel_basic&lt;&#x2F;code&gt; types, which are easy to bring across, but
also &lt;code&gt;Alter&lt;&#x2F;code&gt;, &lt;code&gt;Query&lt;&#x2F;code&gt;, and the like, and the &lt;code&gt;CastleRights&lt;&#x2F;code&gt; structure.&lt;&#x2F;p&gt;
&lt;p&gt;I think &lt;code&gt;-basic&lt;&#x2F;code&gt; is rapidly coinciding with &lt;code&gt;-core&lt;&#x2F;code&gt;, and probably has a better name than either out there. I think there
are these approaches:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Make &lt;code&gt;Cache&lt;&#x2F;code&gt; key-agnostic, instead of doing any more reorganizing, just make it generic. Originally I had wanted the
key-building part to be transparent, but I don’t really do that anymore, so making it fully generic may be worth it.&lt;&#x2F;li&gt;
&lt;li&gt;Move &lt;code&gt;Zobrist&lt;&#x2F;code&gt; to &lt;code&gt;-util&lt;&#x2F;code&gt; or it’s own crate, moving the various stuff it depends on in &lt;code&gt;-core&lt;&#x2F;code&gt; to &lt;code&gt;-basic&lt;&#x2F;code&gt;; this’d
mean &lt;code&gt;interface&lt;&#x2F;code&gt;, &lt;code&gt;PositionMetadata&lt;&#x2F;code&gt;, and &lt;code&gt;CastleRights&lt;&#x2F;code&gt; move to &lt;code&gt;-basic&lt;&#x2F;code&gt;, then &lt;code&gt;-core&lt;&#x2F;code&gt; would pull in and set
&lt;code&gt;HazelZobrist&lt;&#x2F;code&gt;, everything else would end up in the destination crate.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;After all this is done, it leaves:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Board Representation&lt;&#x2F;li&gt;
&lt;li&gt;Move Representation&lt;&#x2F;li&gt;
&lt;li&gt;Position Representation&lt;&#x2F;li&gt;
&lt;li&gt;GameState Representation&lt;&#x2F;li&gt;
&lt;li&gt;some more types that are definitely moving out (log&#x2F;tape&#x2F;etc -&amp;gt; spell, witch -&amp;gt; witch, movesheet -&amp;gt; devnull)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;in &lt;code&gt;-core&lt;&#x2F;code&gt;, at which point I’m forced to ask, ‘what is &lt;code&gt;-core&lt;&#x2F;code&gt; really? &lt;code&gt;-representation&lt;&#x2F;code&gt;’, then &lt;code&gt;hazel-basic&lt;&#x2F;code&gt; -&amp;gt;
&lt;code&gt;hazel-core&lt;&#x2F;code&gt;, and&lt;&#x2F;p&gt;
&lt;p&gt;I also am starting to lean towards having a &lt;code&gt;crates&#x2F;&lt;&#x2F;code&gt; folder, something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assets&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;crates&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hazel&#x2F;              # Main library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bitboard&#x2F;       # bitboard&#x2F;pextboards&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        core&#x2F;           # core types, Square, Color, Direction, Occupant; but also interface stuff (Alter et al)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        engine&#x2F;         # Actor that integrates evaluator and generator and other stuff to play chess&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        evaluator&#x2F;      # Actor that evaluates a set of positions as efficiently as possible.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        generator&#x2F;      # Actor that generates all moves for positions as efficiently as possible.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parser&#x2F;         # Parsers for various chess storage formats (PGN, SAN, etc)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        representation&#x2F; # Representation types for Boards, GameState, Moves, etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ui&#x2F;             # A debugging TUI designed to view the internals of the engine in operation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        util&#x2F;           # Various utility types.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    spell&#x2F;              # Generic &amp;#39;spell&amp;#39; type for reading&#x2F;writing&#x2F;running familiars&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witch&#x2F;              # Generic actor framework&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witchhazel&#x2F;         # Integration point for engine + ui, configuration management, etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;doc&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hooks&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;quals&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tests&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m inclined to push more things down into the core, since I do think a lot of those won’t undergo too much movement
once settled. &lt;code&gt;Alteration&lt;&#x2F;code&gt; is more or less ‘done’, and that is the most mobile of the bunch.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-MAR-2025</title>
        <published>2025-03-27T00:00:00+00:00</published>
        <updated>2025-03-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/27-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/27-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/27-mar-2025/">&lt;h2 id=&quot;1945-spring-cleaning-1&quot;&gt;1945 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;I took a stab over on &lt;code&gt;spring-cleaning-1-parser-twig&lt;&#x2F;code&gt; at pulling out the &lt;code&gt;-parser&lt;&#x2F;code&gt; library, but ran into a number of
issues of where things should be sorted; once I got everything detangled, I was left with some parser bugs and a bad
taste; so I decided to rewind and try again.&lt;&#x2F;p&gt;
&lt;p&gt;Along the way I found that the &lt;code&gt;-engine&lt;&#x2F;code&gt; components are probably going to be simpler to extract first, and then the
parsers after. In particular it’s difficult to have these crates cross boundaries too much before you enter a circular
dependency hell.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to keep working to split out mostly along module lines, if nothing else it’s telling me where all the tight
coupling is.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing I discovered is that the core representation (everything up to and including &lt;code&gt;coup::rep::Move&lt;&#x2F;code&gt;) really
needs to ‘stick together’ – the first logical split point I think is probably at &lt;code&gt;Position&lt;&#x2F;code&gt;. This is a place where
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jfredett&#x2F;tabitha&quot;&gt;tabitha&lt;&#x2F;a&gt; would probably help, since I could see how different modules and structs
tangle with each other.&lt;&#x2F;p&gt;
&lt;p&gt;I also found that my more or less arbitrary use of From&#x2F;Into is resulting in some weird semantics. I think the right way
is to support converting &lt;em&gt;into&lt;&#x2F;em&gt; primitive-ish types (the stuff in -basic), and then have other methods for converting
those things into specific subclasses of a given type; e.g., &lt;code&gt;BEN&lt;&#x2F;code&gt; should have a &lt;code&gt;as_fen_string&lt;&#x2F;code&gt; method; but not a
&lt;code&gt;From&amp;lt;String&amp;gt;&lt;&#x2F;code&gt; implementation. Whereas &lt;code&gt;(Rank, File)&lt;&#x2F;code&gt; should have a &lt;code&gt;From&amp;lt;Square&amp;gt;&lt;&#x2F;code&gt; implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Most of the time I’m asking for &lt;code&gt;anything squarelike&lt;&#x2F;code&gt;, not &lt;code&gt;anything BENlike&lt;&#x2F;code&gt;; though &lt;code&gt;impl Into&amp;lt;BEN&amp;gt;&lt;&#x2F;code&gt; is not uncommon,
I prefer to lean on the &lt;em&gt;trait&lt;&#x2F;em&gt; for that, via &lt;code&gt;impl Query&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll leave the twig up as it may be useful later, but I return to extracting other things now.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>25-MAR-2025</title>
        <published>2025-03-25T00:00:00+00:00</published>
        <updated>2025-03-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/25-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/25-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/25-mar-2025/">&lt;h2 id=&quot;0012-atm&quot;&gt;0012 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been babysitting a file upload most of the night, good time to kick on the playlist and hack.&lt;&#x2F;p&gt;
&lt;p&gt;I got perft fixed up by finding a silly bug in how I reported &lt;code&gt;length&lt;&#x2F;code&gt; from the tape. It’s a little ambiguous, but at
least it works.&lt;&#x2F;p&gt;
&lt;p&gt;I can now fail perft_4 in ~35s, wall-time for the unoptimized test binary, anyway. That’s down from ‘well over 3
minutes’ by a factor of 6 or so, not bad for a &lt;code&gt;HashMap&lt;&#x2F;code&gt; backed cache it only took me a full month to hack together. :)&lt;&#x2F;p&gt;
&lt;p&gt;Next, spring cleaning. I’m going to live with the lack of tests because I’m going to move to rs-test, and start building
some fixtures for more efficient testing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1122-spring-cleaning-1&quot;&gt;1122 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;Started spring cleaning, this is phase 1, which is just getting the workspace going and starting to split out crates and
cleanup dependencies. I’ve done the easiest split so far, into &lt;code&gt;-core&lt;&#x2F;code&gt; and &lt;code&gt;-ui&lt;&#x2F;code&gt; crates; and ran &lt;code&gt;cargo-udeps&lt;&#x2F;code&gt; to clear
out unused dependencies. So far, I’ve brought a clean compile (measured by &lt;code&gt;cargo clean ; time cargo build&lt;&#x2F;code&gt;) from ~37s
-&amp;gt; ~25s, about a 40% reduction.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to continue splitting, but the overall workspace is going to look something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hazel&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hazel-core&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            lib.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            some-module&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                mod.rs      # Quickcheck properties in an embedded module &amp;quot;properties&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                test.rs     # Unit tests for the module, driven by rstest fixtures&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        test&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # core-specific integration tests, driven by rstest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hazel-ui&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # similar layout to the above, but backed also by `insta`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hazel-*&#x2F;            # other crates as needed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hooks&#x2F;              # Profile hook programs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    quals&#x2F;              # Qualification tests, comparing to other engines, establishing Elo, etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    benchmarks&#x2F;         # Performance tests&#x2F;data gathering&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tests&#x2F;              # Integration tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m debating following &lt;code&gt;rust-gpu&lt;&#x2F;code&gt;’s example and putting the crates south of a &lt;code&gt;crates&#x2F;&lt;&#x2F;code&gt; folder, but for the moment I
don’t mind just having them toplevel.&lt;&#x2F;p&gt;
&lt;p&gt;Part of the work so far moved over some ratatui stuff to the ui crate, which changed some apis around, but so far it’s
mostly been mechanical.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1150-spring-cleaning-1&quot;&gt;1150 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;I tried to extract the &lt;code&gt;constants&lt;&#x2F;code&gt; module, but it tangles pretty tightly with other chunks of the system, and extracting
them will be a little tricky. It’s actually a little tricky to extract anything right now because it all
cross-references pretty freely. I think the way out of that is to push more of the code to rely on the interfaces in
&lt;code&gt;src&#x2F;interface&lt;&#x2F;code&gt;, and have &lt;em&gt;that&lt;&#x2F;em&gt; become &lt;code&gt;hazel-core&lt;&#x2F;code&gt;, and then the other hazel crates rely on the interface, and we have
a delightfully decoupled thing. Ultimately this will mean there is a &lt;code&gt;hazel-representation&lt;&#x2F;code&gt; crate which implements the
interfaces, and then that should be replacable when I come up with better representations.&lt;&#x2F;p&gt;
&lt;p&gt;He said, full of dumb hope.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1727-spring-cleaning-1&quot;&gt;1727 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, two more crates split out, &lt;code&gt;hazel-bitboard&lt;&#x2F;code&gt; has all the pretty static bitboard related stuff, &lt;code&gt;hazel-basic&lt;&#x2F;code&gt; has
all the piece&#x2F;color&#x2F;square&#x2F;etc types.&lt;&#x2F;p&gt;
&lt;p&gt;Next I think I’m going to start scaffolding the integration test crate, which can hold the last item in &lt;code&gt;-core&lt;&#x2F;code&gt;’s
constants module. I’ll then turn that module into a re-export module maybe, idk.&lt;&#x2F;p&gt;
&lt;p&gt;I want to split the parser stuff as well, as that should reduce more of &lt;code&gt;-core&lt;&#x2F;code&gt;’s dependencies, but getting &lt;code&gt;-basic&lt;&#x2F;code&gt; and
&lt;code&gt;-bitboard&lt;&#x2F;code&gt; extracted will make that process easier I think.&lt;&#x2F;p&gt;
&lt;p&gt;The end of all this should be a &lt;code&gt;hazel::toolbox&lt;&#x2F;code&gt; module that I can import and get all the basic constants and types for
doing ‘normal’ stuff in &lt;code&gt;hazel&lt;&#x2F;code&gt; the eventual &lt;code&gt;engine&lt;&#x2F;code&gt; crate will have the bits for running the game using the
representation provided by that &lt;code&gt;toolbox&lt;&#x2F;code&gt; module.&lt;&#x2F;p&gt;
&lt;p&gt;Separating the parser should eliminate the &lt;code&gt;nom&lt;&#x2F;code&gt; and similar deps. Separating the engine will probably involve
separating out the &lt;code&gt;witch&lt;&#x2F;code&gt; thing to it’s own crate as well, and hopefully that’ll leave the &lt;code&gt;types&lt;&#x2F;code&gt; module pretty thin
and maybe removable.&lt;&#x2F;p&gt;
&lt;p&gt;So far so good, phase 2 will be &lt;code&gt;rstest&lt;&#x2F;code&gt; and maybe some preliminary benchmarking work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2227-spring-cleaning-1&quot;&gt;2227 - spring-cleaning-1&lt;&#x2F;h2&gt;
&lt;p&gt;I’m settling in on the split, I’m favoring lots of little crates, perhaps to the point of overkill, but at the moment I
prefer to overdo it and pare it back later, it has already paid dividends in terms of clarifying responsibility
barriers, and in service to that I’m going to make a little diagram.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;.&#x2F;assets&#x2F;hazel-crates.png&quot; alt=&quot;a diagram showing the as-built and desired-design of hazel as a multi-crate
workspace&quot; width=&quot;1024&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s in &lt;code&gt;assets&#x2F;hazel-crates.png&lt;&#x2F;code&gt; if that isn’t rendering for whatever reason.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>24-MAR-2025</title>
        <published>2025-03-24T00:00:00+00:00</published>
        <updated>2025-03-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/24-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/24-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/24-mar-2025/">&lt;h2 id=&quot;1406-atm&quot;&gt;1406 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m getting close to scrapping the current Position implementation. I think in order to move to the Familiar-based
approach, it may be sensible to take that route, since it removes some of the internal hash calculation stuff and
&lt;em&gt;should&lt;&#x2F;em&gt; result in a smoother experience. Right now I end up with a lot of little logical errors everywhere because
multiple different codepaths are trying to keep track of a gamestate. I started extracting this (based on the
&lt;code&gt;InnerPosition&lt;&#x2F;code&gt; struct), and I think this will make it easier to transfer state around (just send a quintessence and a
reference-by-hash to the relevant tape.&lt;&#x2F;p&gt;
&lt;p&gt;The ergonomics are such that I may try blanking the relevant tests, merging as-is, and then doing the split. I’m going
to see how close I can get to working again, but I’m itching to do some sanding on this to get the rough spots down.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1519-atm&quot;&gt;1519 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;There is definitely an errant cache hit, and naturally the easiest thing to do is to create a UI widget to see the
internal state of the cache, but once again that returns me to the same problem of the UI side of things being pretty
messy.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# In the `zobrist_is_same_for_transposition` test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ... before this, I construct a transposed version of the position. The final position is the same FEN, but the route&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# to get there is different&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.610727Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Making move: d2 (11) -&amp;gt; d4 (27) (QUIET) [0o026660]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.610836Z DEBUG zobrist_is_same_for_transposition: hazel::game::chess::position: making: d2 (11) -&amp;gt; d4 (27) (QUIET) [0o026660]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.610928Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Caching&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Right here I get a cache hit but it&amp;#39;s wrong, this has cached the position _after 1... d5_ as if it were the position&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# after 1. d4.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611145Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Cache hit Z|0x49B41FB4723326D3| -&amp;gt; &amp;quot;rnbqkbnr&#x2F;pppppppp&#x2F;8&#x2F;8&#x2F;3P4&#x2F;8&#x2F;PPP1PPPP&#x2F;RNBQKBNR b KQkq d3 0 1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611206Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Making move: g8 (62) -&amp;gt; f6 (45) (QUIET) [0o175320]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611249Z DEBUG zobrist_is_same_for_transposition: hazel::game::chess::position: making: g8 (62) -&amp;gt; f6 (45) (QUIET) [0o175320]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611292Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Caching&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611397Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Cache hit Z|0x7AE74C1F751CA0F1| -&amp;gt; &amp;quot;rnbqkbnr&#x2F;ppp1pppp&#x2F;8&#x2F;3p4&#x2F;3P4&#x2F;8&#x2F;PPP1PPPP&#x2F;RNBQKBNR w KQkq d6 0 2&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611442Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Making move: c1 (02) -&amp;gt; f4 (29) (QUIET) [0o004720]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T19:14:34.611481Z DEBUG zobrist_is_same_for_transposition: hazel::game::chess::position: making: c1 (02) -&amp;gt; f4 (29) (QUIET) [0o004720]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Not yet sure why it’s calculating the same hash for that position, I suspect it’s probably some side-to-move malarky. I
should be able to drop the &lt;code&gt;Turn&lt;&#x2F;code&gt; marker and instead use the fact that Assert&#x2F;Inform wraps each move, that should mean I
can do my STM on&#x2F;off through those.&lt;&#x2F;p&gt;
&lt;p&gt;I definitely could benefit from a Cache-browser widget for this, but I think getting into the Actor-y stuff seems most
interesting right now anyway, so I’ll probably pack this up and merge it if I can’t fix this easily.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1834-atm&quot;&gt;1834 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I tweaked to remove the update on &lt;code&gt;Turn&lt;&#x2F;code&gt; and replaced it with full metadata updates on &lt;code&gt;Inform&#x2F;Assert&lt;&#x2F;code&gt;, as I mentioned
before. Doesn’t solve the immediate problem but does resolve one of the hash_familiar tests.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1953-atm&quot;&gt;1953 - atm&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.072518Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Making move: d2 (11) -&amp;gt; d4 (27) (QUIET) [0o026660]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.072750Z DEBUG zobrist_is_same_for_transposition: hazel::game::chess::position: making: d2 (11) -&amp;gt; d4 (27) (QUIET) [0o026660]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.072892Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Caching&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073106Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Cache miss&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073196Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Turn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073243Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Assert &amp;lt;w KQkq - 0 1&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073324Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position_metadata: My meta: w KQkq - 0 1, their meta: w KQkq - 0 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073370Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Remove P @ d2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073430Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Place P @ d4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073472Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Inform &amp;lt;b KQkq d3 0 1&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073547Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: updated inner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073650Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Cache set Z|0x175357BEF46D03ED| -&amp;gt; &amp;quot;rnbqkbnr&#x2F;pppppppp&#x2F;8&#x2F;8&#x2F;3P4&#x2F;8&#x2F;PPP1PPPP&#x2F;RNBQKBNR b KQkq d3 0 1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.073721Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Tape is: 0x42356324111111110000000000000000000000000000000077777777a89bc98a:w KQkq - 0 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PositionZobrist { current: Z|0xB2390A8808563F88|, position: Z|0x175357BEF46D03ED| }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RwLock { data: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TAPE(head_hash: Z|0xB2390A8808563F88|, head: 0x27, hwm: 0x27)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000000 | Clear | Z|0x0000000000000000|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000001 | Place R @ a1 | Z|0xF8F96A2C09E4AF7E|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000002 | Place N @ b1 | Z|0xEA58B07658FE5BEA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000003 | Place B @ c1 | Z|0x4929572CE96AC736|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000004 | Place Q @ d1 | Z|0xD80F29D8B72E614D|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000005 | Place K @ e1 | Z|0x407EFBE89EB626EA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000006 | Place B @ f1 | Z|0x82E8D8D87B2DF6B8|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000007 | Place N @ g1 | Z|0x246E9B437DAE2756|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000008 | Place R @ h1 | Z|0xDA8B17A14E032698|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000009 | Place P @ a2 | Z|0xE13AC46130BCA406|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000A | Place P @ b2 | Z|0xC09F69247A322979|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000B | Place P @ c2 | Z|0x423E7386EE621B94|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000C | Place P @ d2 | Z|0x06F4427BB3BBFA4B|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000D | Place P @ e2 | Z|0xF7C662F78033FE6D|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000E | Place P @ f2 | Z|0x33FF1E11437B3BB5|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000F | Place P @ g2 | Z|0x4488A0019704DF24|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000010 | Place P @ h2 | Z|0xF9569451BA88BDBE|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000011 | Place p @ a7 | Z|0x560A2845D85A8564|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000012 | Place p @ b7 | Z|0x174477C88AD15BCD|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000013 | Place p @ c7 | Z|0x52788A0CCA3D5708|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000014 | Place p @ d7 | Z|0x864346235FD05CED|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000015 | Place p @ e7 | Z|0x44F8C4E79659D080|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000016 | Place p @ f7 | Z|0x136DFFF91DDB872C|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000017 | Place p @ g7 | Z|0x857658D3FD60A795|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000018 | Place p @ h7 | Z|0x6E7BB19382E73A5A|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000019 | Place r @ a8 | Z|0x18603AEEAAEC7478|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001A | Place n @ b8 | Z|0xA020A28F27D57B0A|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001B | Place b @ c8 | Z|0xBC72A17411A7839D|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001C | Place q @ d8 | Z|0x0FD353607E034BD1|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001D | Place k @ e8 | Z|0xF93226BEA0E8522A|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001E | Place b @ f8 | Z|0x5FD9F939C87C647E|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001F | Place n @ g8 | Z|0xB1484F2F5287B45C|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000020 | Place r @ h8 | Z|0x816A59230F79B9AA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000021 | Inform &amp;lt;w KQkq - 0 1&amp;gt; | Z|0x175357BEF46D03ED|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000022 | Turn | Z|0x175357BEF46D03ED|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000023 | Assert &amp;lt;w KQkq - 0 1&amp;gt; | Z|0x816A59230F79B9AA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000024 | Remove P @ d2 | Z|0xC5A068DE52A05875|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000025 | Place P @ d4 | Z|0x46776A46D78D19A7|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000026 | Inform &amp;lt;b KQkq d3 0 1&amp;gt; | Z|0xB2390A8808563F88|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;END-OF-TAPE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;, poisoned: false, .. }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074220Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Making move: d7 (51) -&amp;gt; d5 (35) (QUIET) [0o147060]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074287Z DEBUG zobrist_is_same_for_transposition: hazel::game::chess::position: making: d7 (51) -&amp;gt; d5 (35) (QUIET) [0o147060]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074354Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Caching&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074452Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Cache miss&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074500Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Turn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074530Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Assert &amp;lt;b KQkq d3 0 1&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074572Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position_metadata: My meta: b KQkq - 0 1, their meta: b KQkq d3 0 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074642Z ERROR zobrist_is_same_for_transposition: hazel::game::chess::position_metadata: Incorrect metadata, Found: b KQkq d3 0 1, expected b KQkq - 0 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074723Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Remove p @ d7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074760Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Place p @ d5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074793Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Applying: Inform &amp;lt;w KQkq d6 0 2&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074837Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: updated inner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;### Note the hash, 0xB239... this hash is associated with the move after 1... d5.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074911Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Cache set Z|0xB2390A8808563F88| -&amp;gt; &amp;quot;rnbqkbnr&#x2F;ppp1pppp&#x2F;8&#x2F;3p4&#x2F;3P4&#x2F;8&#x2F;PPP1PPPP&#x2F;RNBQKBNR w KQkq d6 0 2&amp;quot; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2025-03-24T23:51:55.074985Z TRACE zobrist_is_same_for_transposition: hazel::game::chess::position: Tape is: 0x42356324111111110000000000000000000000000000000077777777a89bc98a:w KQkq - 0 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PositionZobrist { current: Z|0x75AB520EB7FCDCCB|, position: Z|0xB2390A8808563F88| }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RwLock { data: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TAPE(head_hash: Z|0x75AB520EB7FCDCCB|, head: 0x2c, hwm: 0x2c)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000000 | Clear | Z|0x0000000000000000|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000001 | Place R @ a1 | Z|0xF8F96A2C09E4AF7E|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000002 | Place N @ b1 | Z|0xEA58B07658FE5BEA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000003 | Place B @ c1 | Z|0x4929572CE96AC736|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000004 | Place Q @ d1 | Z|0xD80F29D8B72E614D|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000005 | Place K @ e1 | Z|0x407EFBE89EB626EA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000006 | Place B @ f1 | Z|0x82E8D8D87B2DF6B8|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000007 | Place N @ g1 | Z|0x246E9B437DAE2756|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000008 | Place R @ h1 | Z|0xDA8B17A14E032698|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000009 | Place P @ a2 | Z|0xE13AC46130BCA406|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000A | Place P @ b2 | Z|0xC09F69247A322979|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000B | Place P @ c2 | Z|0x423E7386EE621B94|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000C | Place P @ d2 | Z|0x06F4427BB3BBFA4B|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000D | Place P @ e2 | Z|0xF7C662F78033FE6D|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000E | Place P @ f2 | Z|0x33FF1E11437B3BB5|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00000F | Place P @ g2 | Z|0x4488A0019704DF24|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000010 | Place P @ h2 | Z|0xF9569451BA88BDBE|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000011 | Place p @ a7 | Z|0x560A2845D85A8564|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000012 | Place p @ b7 | Z|0x174477C88AD15BCD|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000013 | Place p @ c7 | Z|0x52788A0CCA3D5708|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000014 | Place p @ d7 | Z|0x864346235FD05CED|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000015 | Place p @ e7 | Z|0x44F8C4E79659D080|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000016 | Place p @ f7 | Z|0x136DFFF91DDB872C|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000017 | Place p @ g7 | Z|0x857658D3FD60A795|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000018 | Place p @ h7 | Z|0x6E7BB19382E73A5A|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000019 | Place r @ a8 | Z|0x18603AEEAAEC7478|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001A | Place n @ b8 | Z|0xA020A28F27D57B0A|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001B | Place b @ c8 | Z|0xBC72A17411A7839D|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001C | Place q @ d8 | Z|0x0FD353607E034BD1|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001D | Place k @ e8 | Z|0xF93226BEA0E8522A|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001E | Place b @ f8 | Z|0x5FD9F939C87C647E|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00001F | Place n @ g8 | Z|0xB1484F2F5287B45C|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000020 | Place r @ h8 | Z|0x816A59230F79B9AA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000021 | Inform &amp;lt;w KQkq - 0 1&amp;gt; | Z|0x175357BEF46D03ED|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000022 | Turn | Z|0x175357BEF46D03ED|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000023 | Assert &amp;lt;w KQkq - 0 1&amp;gt; | Z|0x816A59230F79B9AA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000024 | Remove P @ d2 | Z|0xC5A068DE52A05875|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000025 | Place P @ d4 | Z|0x46776A46D78D19A7|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000026 | Inform &amp;lt;b KQkq d3 0 1&amp;gt; | Z|0xB2390A8808563F88|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;### Note the hash here corresponds to the above, but is incorrect -- it should be further down, on 0x00002B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000027 | Turn | Z|0xB2390A8808563F88|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000028 | Assert &amp;lt;b KQkq d3 0 1&amp;gt; | Z|0x46776A46D78D19A7|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x000029 | Remove p @ d7 | Z|0x924CA66942601242|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00002A | Place p @ d5 | Z|0xDF027ACAEE79DFDA|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00002B | Inform &amp;lt;w KQkq d6 0 2&amp;gt; | Z|0x75AB520EB7FCDCCB|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;END-OF-TAPE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;=================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;, poisoned: false, .. }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That wall of text shows the bug in real time. We can see that the Zobrist it’s using is based on the start of the turn,
not the end of it. So instead of caching the position associated &lt;em&gt;after applying&lt;&#x2F;em&gt; the move, we associate the &lt;em&gt;updated
position&lt;&#x2F;em&gt; with the hash &lt;em&gt;prior to applying&lt;&#x2F;em&gt; the move, which is an off-by-one, essentially. I could fix this by
reintroducing the &lt;code&gt;end&lt;&#x2F;code&gt; command, or by instead ensuring I’m updating the position hash at the &lt;code&gt;Inform&lt;&#x2F;code&gt; step. In reverse,
this will still work, since it will be examining &lt;code&gt;alter.inverse()&lt;&#x2F;code&gt;, which for &lt;code&gt;Assert&lt;&#x2F;code&gt; is &lt;code&gt;Inform&lt;&#x2F;code&gt;, and thus on the
reverse it will still do the right thing cache-wise.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’m going to try to remove &lt;code&gt;Turn&lt;&#x2F;code&gt;, fewer tokens is better, since ultimately I want to encode this into a
bytestream.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2300-atm&quot;&gt;2300 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Had to put things down, but came back, changed the line, and that was it, that was the whole bug. Still 3 broken tests
remaining but very happy to not have to chase that one anymore.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>23-MAR-2025</title>
        <published>2025-03-23T00:00:00+00:00</published>
        <updated>2025-03-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/23-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/23-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/23-mar-2025/">&lt;h2 id=&quot;1317-atm&quot;&gt;1317 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I don’t think there’s going to be an easy way to get the debug frontend set up until I overhaul the UI heavily to be
more async-first. Bear with me while I talk it out.&lt;&#x2F;p&gt;
&lt;p&gt;Basically, in order to handle the input, I need to include some sort of ‘focus’ mechanism so I can still scroll through
the tape, but also enter values, etc. In order to do this I need to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Track which subsection is chosen, easy – I already have a modal enum I can just add another enum to tell me which
part of the UI I’ve got selected.&lt;&#x2F;li&gt;
&lt;li&gt;Harder, I need to then hand off event handling to that subsection&lt;&#x2F;li&gt;
&lt;li&gt;Harder still, I need to do this without interrupting the engine.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is doable if I move to a message-passing&#x2F;multi-process setup, because then I can just have each subcomponent have a
channel for event handling, etc. Getting there is it’s own little project entirely though.&lt;&#x2F;p&gt;
&lt;p&gt;So on that front, I think I’m going to try to do something a little crazy.&lt;&#x2F;p&gt;
&lt;p&gt;I should be able to fix unmake by basically saying, “Recacluate the boardstate from the beginning of the tape each
time.” I don’t think I’m at any risk of overwriting the end of the tape, and I can always make it bigger in the short
term, but I think that might get all the calculations right at the expense of not actually caching out efficiently?&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I want to store the running-hash alongside the alteration in the tape, and I think that model will work a bit
better anyway, most of my widget code is written at the tape level and not the position level, as well, and I think that
might be wrong.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’m going to spend a few cycles trying to fix the code as is, if I can get it right, then I should be able to
get the tests passing and back to working on the engine, I can follow through with my above plan for either the UI or
the more general plan I set up on 14-MAR.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>22-MAR-2025</title>
        <published>2025-03-22T00:00:00+00:00</published>
        <updated>2025-03-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/22-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/22-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/22-mar-2025/">&lt;h2 id=&quot;1227-atm&quot;&gt;1227 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Setting up the input section, and I’m finding the layouts result in the Input-line is off the end of the screen, I’m not
quite sure why as I’m using percentages for almost everything, might just be something with padding? not sure.&lt;&#x2F;p&gt;
&lt;p&gt;Getting input wired up probably also comes with getting better event handling and widget-selection, which leads me
further from the point of this branch, but I suppose I’m just committed to the UI stuff now. I’d rather not merge with
broken tests.&lt;&#x2F;p&gt;
&lt;p&gt;I did put a little work into the perft stuff, but I’m getting a bug where it unwinds too much and ends up running off
the end of the tape. I think fixing that should get perft working back up to perft3.&lt;&#x2F;p&gt;
&lt;p&gt;I have &lt;em&gt;no&lt;&#x2F;em&gt; idea how I’m going to get the &lt;code&gt;perft-in-the-ui&lt;&#x2F;code&gt; working, I think I’ll have to build a specific message +
handler that sends position updates back to the UI as it runs, then the UI can render it and the perft can continue,
it’ll be quite slow, but this isn’t intended for performance, but debugging. Something like a:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Perft&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    initial&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; BEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    depth&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    reply_to&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; TxChannel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Perft&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    pub fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;initial&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Into&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;BEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; RxChannel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; returns both the message to send and the callback channel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; UI then hands the callback channel to the UI widget, which &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; waits asynchronously for a message and updates when it recieves one.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m a little concerned that this approach is going to rapidly devolve into a “Simply rebuild the entire UI to be fully
async in all parts from the get-go”, at which point I may abandon this till I can at least get the tests passing again
and then take a better stab at refactoring. Before I do that level of work on the UI I want to at least (in no
particular order yet):&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Split up the crates&lt;&#x2F;li&gt;
&lt;li&gt;move to rs-test&lt;&#x2F;li&gt;
&lt;li&gt;Unify the variation stuff under the new &lt;code&gt;familiar&lt;&#x2F;code&gt; system and remove the old implementation.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Once that’s done, I can move to a fully asynchronous UI which ‘observes’ the engine state over (ideally) a channel that
is otherwise ignorant of the internals, this &lt;em&gt;should&lt;&#x2F;em&gt; allow the UI to work &lt;em&gt;as I upgrade the engine code&lt;&#x2F;em&gt; via something
like a hot-reload.&lt;&#x2F;p&gt;
&lt;p&gt;My intent is to first support all of UCI, but quickly this will mean a custom protocol for communicating internal engine
state to the UI asynchronously. Ultimately I want the UI to basically hold a finite buffer of updates and try to just
‘keep up’ with the engine, discarding states it can’t get too as it does so.&lt;&#x2F;p&gt;
&lt;p&gt;Input will be collected, categorized, and then notifications sent to various subcomponents of the UI.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-MAR-2025</title>
        <published>2025-03-19T00:00:00+00:00</published>
        <updated>2025-03-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/19-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/19-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/19-mar-2025/">&lt;h2 id=&quot;1600-atm&quot;&gt;1600 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I really need to split this thing into multiple crates, if only so I can more easily skip all the UI tests which, owing
to their ‘compare to a text screenshot’ approach, are pretty brittle when I start working on the UI.&lt;&#x2F;p&gt;
&lt;p&gt;I’m back to working through some of the failed tests, going to hopefully get it back down to just perft failures before
continuing with the UI debugging, ideally to minimize the number of moving bugs when I’m trying to squash the zobrist
caching part of movegen, which is what this whole thing was supposed to be about in the first place.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-MAR-2025</title>
        <published>2025-03-18T00:00:00+00:00</published>
        <updated>2025-03-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/18-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/18-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/18-mar-2025/">&lt;h2 id=&quot;2343-atm&quot;&gt;2343 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;The end-of-tape-nullmove bug does introduce a secondary bug, where it overwrites the A1 square with a knight that does
not unwind when you run back over it. I think I might just clamp the end of the tape so you can’t scroll past the end.
The way the tapereader work sucks in a lot of ways, but it is pretty cool to watch the pieces wiggle around.&lt;&#x2F;p&gt;
&lt;p&gt;The UI is quite messy, and I need to wire up some more controls so I can make better use of the log widget, and also
send messages into the system, then I should be able to get perft working in the UI.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>14-MAR-2025</title>
        <published>2025-03-14T00:00:00+00:00</published>
        <updated>2025-03-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/14-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/14-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/14-mar-2025/">&lt;h2 id=&quot;1056-atm&quot;&gt;1056 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I got it working, mostly. The &lt;code&gt;Table&lt;&#x2F;code&gt; widget is not working as I’d expect, and in particular it seems to have very
little correlation in the number of rows I fetch to the number of rows it renders. I think I may DIY this, I’m not
entirely sure what I’m doing wrong, so building it myself might be an improvement. Also an opportunity to work out the
remaining bugs with the thing. Mostly UX issues, a couple of weird UI bugs as well, and at least one &lt;code&gt;O(n)&lt;&#x2F;code&gt;-growing
repeated call problem when you scroll past the end of the tape.&lt;&#x2F;p&gt;
&lt;p&gt;Separately, I want to integrate a board representation and other diagnostic info before getting to the actual point,
which is debugging &lt;code&gt;perft&lt;&#x2F;code&gt; and the game representation.&lt;&#x2F;p&gt;
&lt;p&gt;I had to compromise a lot on the &lt;code&gt;Tapelike&lt;&#x2F;code&gt; design, mostly due to the way &lt;code&gt;Tape&lt;&#x2F;code&gt; don’t have central
allocation&#x2F;management. Ultimately &lt;code&gt;Tape&lt;&#x2F;code&gt; should reside in some stable memory-space that I can easily refer to across the
application. I’d even like if they were CoW and the ‘&lt;code&gt;TapeDeck&lt;&#x2F;code&gt;’[1]&lt;&#x2F;p&gt;
&lt;p&gt;[1] Name pending, I went with &lt;code&gt;Tape&lt;&#x2F;code&gt; for the tame now, but it doesn’t fit the rest of the naming scheme w&#x2F; familiars and
stuff. &lt;code&gt;Tape&lt;&#x2F;code&gt; is a very Computer-Sciency name for it, I want something more like Computer Witchcraft, so this might get
renamed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1538-atm&quot;&gt;1538 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Continuing: Barring some naming stuff, once I have a situation where I’m storing &lt;code&gt;Tape&lt;&#x2F;code&gt;s in some broader allocation, I
can share reference to subsections of &lt;code&gt;Tape&lt;&#x2F;code&gt; that way. Eventually I think the result will be some storage entity a la
&lt;code&gt;Cache&lt;&#x2F;code&gt; that holds all the tapes and dynamically grabs the right ‘section’ of tape (identified by Zobrist of said tape)
and dynamically creates a &lt;code&gt;Tape&lt;&#x2F;code&gt; with that content as needed. This will also allow the UI a stable reference to a
section of tape.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally this thing is actually just a big &lt;code&gt;Vec&lt;&#x2F;code&gt; of larger contiguous chunks of memory, maybe adding some kind of &lt;code&gt;Jump&lt;&#x2F;code&gt;
alteration to skip around to different subsections within the &lt;code&gt;Tape&lt;&#x2F;code&gt; (so long as the destination had a reversible
&lt;code&gt;Landing&lt;&#x2F;code&gt; instruction, a la &lt;code&gt;COME FROM&lt;&#x2F;code&gt; in Intercal, of all things).&lt;&#x2F;p&gt;
&lt;p&gt;I think getting a board&#x2F;metadata rep connected is the next step, and then I can rig up an IO section for controlling the
engine via uci commands. Once I can do that I should be able to get it hooked up to &lt;code&gt;perft&lt;&#x2F;code&gt; output.&lt;&#x2F;p&gt;
&lt;p&gt;I will need to extend this to a nested reader at some point, connecting a variation-tape to a position-tape and warping
everything around appropriately.&lt;&#x2F;p&gt;
&lt;p&gt;I also really need to overhaul both how communication is handled via &lt;code&gt;Witch&lt;&#x2F;code&gt; (it’s presently handled in a way to mimic a
STDIO&#x2F;UCI style thing, and I’d prefer to have most internal messages be a direct-response-over-a-oneshot-channel, which
will avoid all sorts of race conditions if multiple clients are reading the engine simultaneously), and also refactor
the UI to be a fully asynchronous update&#x2F;event&#x2F;draw loop. Ideally the drawing would be independent of the other two and
support a high-sample-rate of the underlying state, so that the engine is not limited by the UI update speed, which I
suspect will be the case in the current model.&lt;&#x2F;p&gt;
&lt;p&gt;Last, I need to think about what columns make sense in the TapeReader, and also how to render alterations. I know for
sure I need to add a &lt;code&gt;Inform&#x2F;Assert(EnPassant(None))&lt;&#x2F;code&gt; at least for now to make the forward&#x2F;reverse simple, but I suspect
in the longer term I’ll be able to elide much of the metadata alterations.&lt;&#x2F;p&gt;
&lt;p&gt;For now, though, the tapereader basically works (mod bugs), and things are starting to look like how I want them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2352-atm&quot;&gt;2352 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Just documenting some bugs w&#x2F; the tapereaderwidget:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;On first load, shows nothing, this is probably due to how it’s initialized, but the unloaded state should be better
represented.&lt;&#x2F;li&gt;
&lt;li&gt;After loading by pressing ‘down’, it loads and sits on 0x00001, can’t scroll up to 0x00000.
&lt;ul&gt;
&lt;li&gt;I can scroll to 0x00020 later, without issue, so it’s just the 0th entry, not the first entry of a page&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;0x00049 is the actual end of tape, 0x0004A shows a null-place (&lt;code&gt;Place N @ a1&lt;&#x2F;code&gt; maps to &lt;code&gt;0&lt;&#x2F;code&gt; in all fields), so I’m
getting a null that’s interpreted as an alteration even though there isn’t an alteration there (or shouldn’t be,
anyway).&lt;&#x2F;li&gt;
&lt;li&gt;After scrolling past the end of the tape, it seems to have an O(n) increasing number of calls to the page_range
function, which is an issue only if I allow scrolling past the final page&#x2F;scrolling arbitrarily far forward.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Next tasks:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Hook up and provide a gamestate representation attached to the current position. Board, FEN, at least.&lt;&#x2F;li&gt;
&lt;li&gt;Input&#x2F;output section routing to the engine.
&lt;ul&gt;
&lt;li&gt;UCI messages should get rebuilt into &lt;code&gt;WitchHazel&lt;&#x2F;code&gt; messages, ideally with a oneshot return channel, but they also
need to obey the STDIO stuff as well which is going to use the &lt;code&gt;#write&lt;&#x2F;code&gt; method.&lt;&#x2F;li&gt;
&lt;li&gt;Internal messages are more free, and the main ones I’m looking for are probably going to be something like
‘load-from-file’ and ‘perft’ to start. That’ll make it possible to build the stockfish integration test I
described… way back in November…&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Make things look nicer.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>11-MAR-2025</title>
        <published>2025-03-11T00:00:00+00:00</published>
        <updated>2025-03-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/11-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/11-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/11-mar-2025/">&lt;h2 id=&quot;0042-atm&quot;&gt;0042 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m finding it quite difficult to live with my, perhaps ill-adviced&#x2F;anxiety-informed choice to try to avoid &lt;code&gt;Arc&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;Rc&lt;&#x2F;code&gt;
for the &lt;code&gt;Cursor&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;Familiar&lt;&#x2F;code&gt; system, but I think I have met my match with the way things are going with the tape widget.&lt;&#x2F;p&gt;
&lt;p&gt;After a brief diversion to get logging exposed in the UI, I now have an interactive way to debug the damn tape widget.&lt;&#x2F;p&gt;
&lt;p&gt;I finally want to get it hooked up to the actual engine backend using the &lt;code&gt;Witch&lt;&#x2F;code&gt; actor system, but I’m running into a
borrowing issue since I’m now in the multithreaded environment where it gets tricky to pass the data around to be used
by both the engine and the various UI components. Since I want the UI to be able to expose parts of the engine directly
for debugging, I don’t want to rely on copying state across or otherwise processing it, I really want a reference as
close as possible to the ‘real’ thing.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been putting off using any kind of thread-safe stuff because I couldn’t imagine what joint it would make sense to
cut at in terms of thread safety. Too coarse and the system won’t scale, too fine and the system won’t perform. Polya
says if you have a hard problem you can’t solve, find a simpler one you can’t solve; thus everything else up till now.&lt;&#x2F;p&gt;
&lt;p&gt;I have already established one boundary, &lt;code&gt;Hazel&lt;&#x2F;code&gt; is the engine state struct, with &lt;code&gt;Witch&lt;&#x2F;code&gt; surrounding it and managing
message passing. Hazel ultimately will contain a &lt;code&gt;Variation&lt;&#x2F;code&gt;, which encodes a multi-variation game structure as a flat
file[1]. A &lt;code&gt;Familiar&lt;&#x2F;code&gt; on that structure will calculate some chosen &lt;code&gt;Position&lt;&#x2F;code&gt; based on the contents of the &lt;code&gt;Variation&lt;&#x2F;code&gt;
at the chosen point. Similarly, &lt;code&gt;Position&lt;&#x2F;code&gt; compiles &lt;code&gt;Moves&lt;&#x2F;code&gt; and writes them to a &lt;code&gt;Tape&lt;&#x2F;code&gt;[2]. This tape also uses a
&lt;code&gt;Familiar&lt;&#x2F;code&gt; to calculate the current boardstate, potentially jumping to specific states via Zobrist &lt;code&gt;Cache&lt;&#x2F;code&gt; hits.
&lt;code&gt;PositionFamiliar&lt;&#x2F;code&gt;s, in particular, use &lt;code&gt;Bitboard&lt;&#x2F;code&gt;, the &lt;code&gt;Query&lt;&#x2F;code&gt; trait, and ultimately use the &lt;code&gt;Alter&lt;&#x2F;code&gt; trait and it’s
companion &lt;code&gt;Alteration&lt;&#x2F;code&gt; enum to specify incremental, reversible updates. Since &lt;code&gt;Cursor&lt;&#x2F;code&gt;s (and therefore &lt;code&gt;Familiar&lt;&#x2F;code&gt;s) can
also read ranges of the underlying tape, eventually these Familiars can optimize across multiple &lt;code&gt;Alteration&lt;&#x2F;code&gt;s to
minimize computation (e.g., the &lt;code&gt;PawnStructure&lt;&#x2F;code&gt; familiar might ignore all the non-pawn related alterations, and further
use &lt;code&gt;simd&lt;&#x2F;code&gt; to apply multiple alterations at once where possible). All of this is provided via the &lt;code&gt;hazel&lt;&#x2F;code&gt; libary.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;main.rs&lt;&#x2F;code&gt; is then just whatever is necessary to set up a &lt;code&gt;tokio&lt;&#x2F;code&gt; environment and run either the UI or just the UCI
subsystem. The &lt;code&gt;UCI&lt;&#x2F;code&gt; subsytem uses the &lt;code&gt;UCIMessage&lt;&#x2F;code&gt; struct (which sucks) to send UCI messages to the engine via
&lt;code&gt;WitchHazel&lt;&#x2F;code&gt;’s &lt;code&gt;MessageFor&lt;&#x2F;code&gt; trait implementors. Eventually each message will be it’s own type and can contain whatever
logic is needed to move hazel into the implied state in their various impls. Most will be ZSTs, but where natural types
like &lt;code&gt;BEN&lt;&#x2F;code&gt; and such can be used. This will also make it easy to add custom commands to &lt;code&gt;Hazel&lt;&#x2F;code&gt;, which I need for the
eventual database-y features I intend to add.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Familiar&lt;&#x2F;code&gt;s in particular need to be self-contained little guys that ideally can be quickly transferred to any
thread or client &lt;code&gt;Hazel&lt;&#x2F;code&gt; engine. They rely on the &lt;code&gt;Cursor&lt;&#x2F;code&gt; object, and ultimately I think that’s the joint where I need
to start cutting. &lt;code&gt;Cursor&lt;&#x2F;code&gt; presently relies on a simple borrowed reference to talk about it’s target &lt;code&gt;Tapelike&lt;&#x2F;code&gt; object,
but it should probably use an &lt;code&gt;Arc&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, I only have familiars that don’t mutate the underlying variation, I don’t know that I’ll run into a need
to have concurrent writes &lt;em&gt;just&lt;&#x2F;em&gt; yet, and it’s another joint in any case. I &lt;em&gt;think&lt;&#x2F;em&gt; there is some combination of &lt;code&gt;Arc&lt;&#x2F;code&gt;
and &lt;code&gt;RwLock&lt;&#x2F;code&gt; that might make sense for cursor, but I need to think on it.&lt;&#x2F;p&gt;
&lt;p&gt;I think this should also clean up the types a bit and avoid all the lifetime math I’ve been doing, since I can just
clone an &lt;code&gt;Arc&lt;&#x2F;code&gt; around without the same anxiety that cloning a big &lt;code&gt;Tape&lt;&#x2F;code&gt; gives me.&lt;&#x2F;p&gt;
&lt;p&gt;Once &lt;em&gt;all&lt;&#x2F;em&gt; of that refactoring is done, I will &lt;em&gt;finally&lt;&#x2F;em&gt; be able to finish the &lt;code&gt;TapeReader&lt;&#x2F;code&gt; widget, since it will rely on
a &lt;code&gt;TapeFamiliar&lt;&#x2F;code&gt;[3] instead of this crazy reference lifetime rigamarole I’ve been trying to massage into shape.&lt;&#x2F;p&gt;
&lt;p&gt;The remaining problems to solve I see are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Getting the UCI Implementation working (as always).&lt;&#x2F;li&gt;
&lt;li&gt;Some mechanism for managing a familiars and states
&lt;ul&gt;
&lt;li&gt;In particular, the &lt;code&gt;TapeReader&lt;&#x2F;code&gt; can only show it’s own position, but I will want to be able to have the result of
other familiars operating on the tape simultaneously shown on a single widget.&lt;&#x2F;li&gt;
&lt;li&gt;I also want to be able to independently manage a particular familiar (as in, the API wrapping a particular
state-object with a cursor onto some other object) with the actual cursor that ‘powers’ it. In this way I can better
batch different needs of the engine. If multiple lines all want to calculate through some particular position, I can
prioritize unblocking those threads dynamically. This is the plan, anyway.&lt;&#x2F;li&gt;
&lt;li&gt;It will &lt;em&gt;also&lt;&#x2F;em&gt; enable the UI to have a &lt;code&gt;Menagerie&lt;&#x2F;code&gt; of familiars it can then loan the state of to each of the
widgets.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Hook up the &lt;code&gt;Board&lt;&#x2F;code&gt; widget to a syncronized &lt;code&gt;Familiar&lt;&#x2F;code&gt; with &lt;code&gt;TapeReader&lt;&#x2F;code&gt;, and we should get the engine’s idea of the
current selected boardstate.&lt;&#x2F;li&gt;
&lt;li&gt;Write some command that runs &lt;code&gt;perft&lt;&#x2F;code&gt; in the engine so we can watch it blow up.&lt;&#x2F;li&gt;
&lt;li&gt;…&lt;&#x2F;li&gt;
&lt;li&gt;Well, I can’t say profit, but it’ll be cool to watch the pieces move around. Very &lt;code&gt;blinkenlights&lt;&#x2F;code&gt;, very cool.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Anyway – the point of this is &lt;em&gt;that’s it&lt;&#x2F;em&gt;, that’s the whole system I have conceived up to this point. I took time to
work on &lt;code&gt;tabitha&lt;&#x2F;code&gt; trying to figure out that, and though I haven’t finished her yet, she ended up not being totally
necessary. There are a few missing types I didn’t mention in there (&lt;code&gt;Square&lt;&#x2F;code&gt; is probably the only notable omission, but
it’s not really a type, just a notational convenience in the engine), but it covers the design as is. I am pretty close,
I think, to getting that working and getting to at least step 1 (or 2) with a little more refactoring and a finished
cache implementation, which should come quickly when I finish the debugging tool intended to fix it.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s hope I don’t go walkabout first.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;[1] Variation presently uses an early iteration of the &lt;code&gt;Tapelike&lt;&#x2F;code&gt; interface and all that, it needs to be unified to this
model and also to use the &lt;code&gt;Tape&lt;&#x2F;code&gt; structure, enhanced with some write-to-disk functionality added.&lt;&#x2F;p&gt;
&lt;p&gt;[2] The same cache-to-disk functionality can be applied to any particular &lt;code&gt;Tape&lt;&#x2F;code&gt;, but with a target of an in-memory
cache.&lt;&#x2F;p&gt;
&lt;p&gt;[3] &lt;code&gt;type TapeFamiliar&amp;lt;S&amp;gt; = forall T : Tapelike, Familiar&amp;lt;T, S&amp;gt;&lt;&#x2F;code&gt; – or whatever rust has for that, I think.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1033-atm&quot;&gt;1033 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Started working on the refactor, I decided to just go ahead an do an &lt;code&gt;Arc&amp;lt;RwLock&amp;lt;T&amp;gt;&amp;gt;&lt;&#x2F;code&gt; on &lt;code&gt;Cursor&lt;&#x2F;code&gt;, but not provide a
write API for now. I think ultimately I’ll want to put the write API on the cursor itself, but for now it mostly aids in
sharing the already RwLock’d tape inside position. I am also going to &lt;code&gt;Arc&lt;&#x2F;code&gt; that &lt;code&gt;tape&lt;&#x2F;code&gt; instance in &lt;code&gt;Position&lt;&#x2F;code&gt;, which
makes creating the cursor very easy (cursor just clones the &lt;code&gt;tape&lt;&#x2F;code&gt;, but the tape is owned by &lt;code&gt;Position&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1046-atm&quot;&gt;1046 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m also ripping out all the hash calculation on &lt;code&gt;tape&lt;&#x2F;code&gt;, I’m going to manage this via familiars still, but I want them
to exist outside tape itself, which should be agnostic with respect to it’s contents.&lt;&#x2F;p&gt;
&lt;p&gt;The only place where I’m a little hesitant is the &lt;code&gt;head_hash&lt;&#x2F;code&gt;, which is used for tape-level cache-out, but I think the
cacheout can just calculate this at cache-out time from scratch (no incremental maintenance), since the array is small
this works out to a pretty small number of operations done rarely, which I think is probably fine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2049-atm&quot;&gt;2049 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve found that, in fact, what I’m trying to do is impossible, and needs some additional state. In particular, I’m
reinventing the &lt;code&gt;owning_ref&lt;&#x2F;code&gt; crate. Ultimately, I want to only allocate the underlying &lt;code&gt;Tape&lt;&#x2F;code&gt;’s memory &lt;em&gt;once&lt;&#x2F;em&gt;, living in
an (eventually not &lt;code&gt;&#x27;static&lt;&#x2F;code&gt; &lt;code&gt;Cache&lt;&#x2F;code&gt; shared amongst threads and owned by the parent thread behind a tokio wrapper so
that it is accessible across networked clients as well).&lt;&#x2F;p&gt;
&lt;p&gt;I’m also starting to get frustrated with the compile time cycle. I think there are a few things to look into. First is
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;benw.is&#x2F;posts&#x2F;how-i-improved-my-rust-compile-times-by-seventy-five-percent&quot;&gt;this&lt;&#x2F;a&gt; and it’s followup to
investigate. I’m already on nightly with all the stripes painted on the side, so I don’t mind being experimental. I
think &lt;code&gt;mold&lt;&#x2F;code&gt; was set up at least when I was still using the other shell framework, but I’ll have to spend a cycle or two
refactoring. I also suspect moving to a workspace and separating out some of the crates might mean I can cut some
dependencies out and speed things up.&lt;&#x2F;p&gt;
&lt;p&gt;Add it to the bucketlist.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2119-atm&quot;&gt;2119 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, I think I’ve ended up on a rabbit trail. I’m also in a bit of a pickle with respect to the repo, I need to commit
off some of the UI work, and then I think revert a bit and take a fresh stab at the Familiar&#x2F;Cursor&#x2F;Tape stuff.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, this arose while trying to get the &lt;code&gt;TapeReader&lt;&#x2F;code&gt; widget working, which was exhibiting extremely strange
bugs, that ultimately were down to the scaffolded way I had wired it in re-building the widget every &lt;code&gt;draw&lt;&#x2F;code&gt; call.&lt;&#x2F;p&gt;
&lt;p&gt;The idea was to connect it to the engine, which exposed issues with &lt;code&gt;tokio&lt;&#x2F;code&gt; and how the UI connects to the backend, and
thus all this other work.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to get the commits done, then start over on this setup. I think the rough heirarchy still makes sense, but I
need to push some of the concurrency around and that requires a redesign.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>9-MAR-2025</title>
        <published>2025-03-09T00:00:00+00:00</published>
        <updated>2025-03-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/9-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/9-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/9-mar-2025/">&lt;h2 id=&quot;0034-atm&quot;&gt;0034 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Working a bit more, I’ve got the tape widget kind of working, but the &lt;code&gt;Table&lt;&#x2F;code&gt; widget has some slightly strange behavior
that I can’t &lt;em&gt;quite&lt;&#x2F;em&gt; say is it’s fault, but I don’t see where the issue is on my side.&lt;&#x2F;p&gt;
&lt;p&gt;It’s an easy problem to fix, though, DIY.&lt;&#x2F;p&gt;
&lt;p&gt;I am starting to think that I should build my actual Widgets to be the payload of a Familiar, using a similar
update-override, I could have a &lt;code&gt;Widgety&lt;&#x2F;code&gt; trait that adds an advance&#x2F;retreat logic to update it’s internal state, and
then a parent widget can just manage advancing&#x2F;retreating whatever widget needs said advancing&#x2F;retreating.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>6-MAR-2025</title>
        <published>2025-03-06T00:00:00+00:00</published>
        <updated>2025-03-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/6-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/6-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/6-mar-2025/">&lt;h2 id=&quot;1354-atm&quot;&gt;1354 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Noticed a little bug, if you place two places to the same square in a row, it will happily ‘place’ the piece in the
square, screw up the zobrist, and then move along. This is happening in the current (46da817) SHA, though I honestly
don’t know &lt;em&gt;why&lt;&#x2F;em&gt; it’s making multiple &lt;code&gt;place&lt;&#x2F;code&gt; commands there, it is. Maybe because it’s initializing to zeroes and
trying to read them as &lt;code&gt;None&lt;&#x2F;code&gt;s? IDK. Might be worthwhile to add an &lt;code&gt;Alteration::Noop&lt;&#x2F;code&gt; in the mix and get rid of the
&lt;code&gt;Option&lt;&#x2F;code&gt; type entirely in &lt;code&gt;Tape&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next steps are to continue refactoring, I realized that by adding some additional methods to the familiar, I can get the
best of both worlds, update the state via the simple &lt;code&gt;Alter&lt;&#x2F;code&gt; code, then when the UI needs to read context data, it talks
to the familiar, which can specialize the methods according to it’s current position&#x2F;state. This means that &lt;code&gt;Familiar&lt;&#x2F;code&gt;
will proxy some of &lt;code&gt;Cursorlike&lt;&#x2F;code&gt; and &lt;code&gt;Tapelike&lt;&#x2F;code&gt; to the end user, but with the added context of the familiar’s state,
which I think should be plenty for what I need. I am going to aim to build up the &lt;code&gt;TapeReaderState&lt;&#x2F;code&gt; with the new
familiar system and see how that fares.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1936-atm&quot;&gt;1936 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I was thinking a bit about &lt;code&gt;Zobrist&lt;&#x2F;code&gt; while organizing code, and I think I want to tweak the design. I’m planning to use
&lt;code&gt;Zobrist&lt;&#x2F;code&gt; for much more than just position hashing, since I can certainly use them for &lt;code&gt;Tape&lt;&#x2F;code&gt; caching at least, and
perhaps for other things as well. I also expect I’ll want to use them primarily in the context of a Cache, so I want to
tie those things together and also ensure the type system prevents using the wrong calculated hash, since they all look
pretty much the same. I’d also like to be able to tweak the seed per cache, since the behavior is quite sensitive to
what it is you’re hashing.&lt;&#x2F;p&gt;
&lt;p&gt;I’m thinking of taking a phantom type, at the very least, on both &lt;code&gt;Cache&lt;&#x2F;code&gt; and &lt;code&gt;Zobrist&lt;&#x2F;code&gt;. Cache will accept lookups only
with matching type. I can also use that phantom type information to report back to the debug UI and log as telemetry
about the hashes, which I can then use to start analyzing hash quality, which I think will be important. I think this
will be a good way to implement things when I get to actually implementing a non-stub version of &lt;code&gt;Cache&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Unrelated, I need to put some kind of prelude module together, there is a set of common things (Square constants,
macros, some types) that I simply need all the time, and more generally it’d be good to have some sort of toolbox module
that just reexports all the stuff I need. I have been idling on splitting up the thing into multiple crates, LSP is
getting quite slow and I think it’s potentially due to project structure – it’s also just getting a bit messy, and some
parts of the system are quite stable and unlikely to change until I get into the optimization loop later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1953-atm&quot;&gt;1953 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m procrastinating, but I thought of a potentially interesting game&#x2F;tool for teaching chess to children. My kid is
almost four, and loves watching me play chess, despite constant protestation about not playing illegal moves. I’ve been
thinking about how I will teach the game, and when it comes to teaching, my style is somewhat idiosyncratic. I dislike
direct instruction and generic or trite metaphors. Rarely do these appeal to the actual individual learning in front of
you, and they always seem to focus on creating a superficial understanding that does not really drive nor reward
discovering better abstractions later.&lt;&#x2F;p&gt;
&lt;p&gt;Take, for example, chess puzzles. I love them now, but hated them at first because they didn’t make sense – I didn’t
understand what they were aiming to reinforce or teach, because I was hung up on the idea that I was simply supposed to
play ‘well’ and not ‘accurately’, puzzles reward accurate identification of tactical sequences and execution of those
sequences (“combination”). By directing a student to a puzzle which has the full rules of chess enforced, probably with
many pieces to consider, and then to expect them to just ‘caclulate’ leads to frustration. This is mitigated either by
replacing the puzzle with simpler ones, which is demoralizing for many students (myself included); or by starting with
trivial puzzles (which don’t really help develop the muscles for real games, which is the typical goal of students
(myself not included)) and progressively increasing difficulty, which delays the value of the puzzle and makes it hard
to understand how it’s helping; or by carefully walking them through the puzzle and emphasizing calculation and patience
and how to look for tactics and so on. This is probably our best try, but it still leaves the game badly unbalanced, the
amount of &lt;em&gt;work&lt;&#x2F;em&gt; it takes to drag a student through the weight of all the possibilities is highly inefficient.&lt;&#x2F;p&gt;
&lt;p&gt;The problem is not the student nor the teacher, it’s the rules. There are two many of them to easily isolate tactics in
a narrow space that makes calculation easy. Most small-piececount puzzles in chess are either trivial mates&#x2F;forks, or
pawn-and-piece endgames which are renowned for being calculation intense, as the branching factor shrinks, allowing a
great deal of depth, paradoxically &lt;em&gt;increasing&lt;&#x2F;em&gt; the number of positions that must be considered.&lt;&#x2F;p&gt;
&lt;p&gt;The rules are also against us because the &lt;em&gt;best&lt;&#x2F;em&gt; tactical positions are also the &lt;em&gt;narrowest&lt;&#x2F;em&gt;. These offer the most
excitement, snatching victory from the jaws of utter defeat. A mate-or-be-mated position is &lt;em&gt;thrilling&lt;&#x2F;em&gt;, and excitement
cements memory like nothing else. So we want to reduce the resistance and ensure early and frequent narrow wins. We, as
teachers, can then slowly increase the difficulty and lower the win rate, and ultimately develop the mental muscles of
our student.&lt;&#x2F;p&gt;
&lt;p&gt;So what if we isolate tactics into smaller rulesets built around simpler games? Let’s also try to make the game slightly
asymmetric, such that the student’s role is easier, we will rely on the skill differential to help balance the game.
We’ll also use an asymmetric clock, so that the stronger player has less time.&lt;&#x2F;p&gt;
&lt;p&gt;The rules of the game are simple, the stronger player takes a king and piece of their choice (not a pawn). The student
takes a piece assigned to them by the stronger player. The stronger player is given a clock, the student may be given a
clock, depending on the stage of training.&lt;&#x2F;p&gt;
&lt;p&gt;Student places their piece on the board.&lt;&#x2F;p&gt;
&lt;p&gt;The teacher goes second and places both of their pieces on the board.&lt;&#x2F;p&gt;
&lt;p&gt;The student must fork the teacher’s pieces. As soon as this happens the game ends and the student wins. If the student’s
piece is captured, they lose. When the student wins, the teacher gains an increment on their clock and the game resets.
When the teacher wins, they lose an increment. Play until you’re done.&lt;&#x2F;p&gt;
&lt;p&gt;The point of the game is just to practice recognizing fork configurations of these pieces on instinct. There is no
attempt to teach deeper chess concepts, it’s just lifting weights.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t know if it’s a good game, but I might make hazel play it someday.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>5-MAR-2025</title>
        <published>2025-03-05T00:00:00+00:00</published>
        <updated>2025-03-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/5-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/5-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/5-mar-2025/">&lt;h2 id=&quot;0058-atm&quot;&gt;0058 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m working on the UI a bit to help get the perft bugs sorted out. I am running into an unfortunate design decision
which leads to some unfortunate type stuff.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally I want a tape to be a static allocation, and have &lt;code&gt;Alterations&lt;&#x2F;code&gt; be encoded to some relatively small
representation (maybe a u16). Encoding this in the type will make it (I hope) easy to tweak later to appease the memory
gods. It’s not premature optimization, it’s optimizating prior to maturity.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, using a const generic seems natural, except that my &lt;code&gt;Familiar&lt;&#x2F;code&gt; type needs to borrow a reference to it, but
that means it needs to name &lt;em&gt;the specific&lt;&#x2F;em&gt; type, not just one of any size, though the reference will be the same for all
of them.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not sure how to fix that, logically I think it’s sound to drop the knowledge of the size of the tape here, but I
can’t think of a way to do that in the type system (mostly due to ignorance, I think it should be possible).&lt;&#x2F;p&gt;
&lt;p&gt;I suppose I could push the generic into the method, which would possible make things easier, I think the easiest way to
address it would be dynamic allocation, but that would set up a bit of a can of worms of how configuration will work. I
still want it to be a single static allocation so I think that’s probably the easiest thing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1022-atm&quot;&gt;1022 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I found &lt;code&gt;dynamic-array&lt;&#x2F;code&gt;, which I’m going to use for now, I think at some point I’ll probably want to implement it by
hand, but for now I just want a dynamic array I don’t have to think about.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1435-atm&quot;&gt;1435 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;dynamic-array&lt;&#x2F;code&gt; was drop in, which was nice, but I am straining against how I’m managing these &lt;code&gt;Familiar&lt;&#x2F;code&gt;s and I think I
need to just bite the bullet and do the refactor. In concept it’s straightforward, it’s a common API for working with
linear data on some kind of tape. &lt;code&gt;Everything is a file&lt;&#x2F;code&gt; extended into Hazel.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Calculates a state based on the content of some tapelike. Importantly, the `cursor` should be _replacable_, so that&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; if a familiar runs off the end of a tape, and we have a continuation for that tape in cache, we can replace it&amp;#39;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; cursor with a new one on the new tape and maintain the state. These should ultimately be sendable between threads, so&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; all their state is maintained internally in a thread-safe way.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Familiar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    state&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; A zipper-type over the Tapelike. Hides locking details from familiar, so that familiar can RW safely.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Eventually will tie into some kind of transaction tool to coordinate concurrent writes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; T&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Tapelike&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    ref&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Arc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;RwLock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    position&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Covers all the IO operations on the tape, without an explicit read&#x2F;write head being maintained.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;trait&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Tapelike&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; locking ranges is internal, ideally takes place transactionally (eventually)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; length&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; read_address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; address&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; read_range&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Range&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; write_address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; address&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; write_range&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; start&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; conjure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;tape&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Familiar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; T&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Tapelike&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;    Familiar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; tape&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cursor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        state&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;this is my rough sketch, I’m not sure I’ve got all the concurrency stuff right there but that’s what compiler errors are
for.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1532-atm&quot;&gt;1532 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Extending the above, the &lt;code&gt;Cursor&lt;&#x2F;code&gt; object would be able to access the whole &lt;code&gt;Tapelike&lt;&#x2F;code&gt; API, which makes me think maybe I
should use an associated constant for the entry type, similar to Iterator, which is kind of what I’m aping here.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>4-MAR-2025</title>
        <published>2025-03-04T00:00:00+00:00</published>
        <updated>2025-03-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/4-mar-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/4-mar-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/4-mar-2025/">&lt;h2 id=&quot;0937-atm&quot;&gt;0937 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m back to the perft bugs with the new &lt;code&gt;Tape&lt;&#x2F;code&gt; implementation. It’s not perfect and needs a ton of sanding, but it’s a
much better and more complete start than I had.&lt;&#x2F;p&gt;
&lt;p&gt;I think the next step is actually going to be wiring this into the UI, so I can manually walk around and watch the perft
happen and try to catch the Tape misbehaving ‘live’. The current bug is definitely just an &lt;code&gt;unmake&lt;&#x2F;code&gt; issue, but hard to
guess from simple trace output, a &lt;code&gt;TapeWidget&lt;&#x2F;code&gt; would be helpful, as well as a better way to manage all the &lt;code&gt;Familiars&lt;&#x2F;code&gt;
surrounding the Tape.&lt;&#x2F;p&gt;
&lt;p&gt;I’m also not correctly processing metadata at the moment, the &lt;code&gt;Inform&lt;&#x2F;code&gt; blocks don’t change the metadata.&lt;&#x2F;p&gt;
&lt;p&gt;So basically, it still doesn’t work, but it doesn’t doesn’t work as doesn’tly as it did didn’t before.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to try to do a little fix-in-place so I can maybe merge this branch before doing more UI stuff, as that’s
going to require building up the communication side of things, and movegen working would help a lot there.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>28-FEB-2025</title>
        <published>2025-02-28T00:00:00+00:00</published>
        <updated>2025-02-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/28-feb-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/28-feb-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/28-feb-2025/">&lt;h2 id=&quot;1836-atm&quot;&gt;1836 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;I’m starting to think about &lt;code&gt;Log&lt;&#x2F;code&gt;, &lt;code&gt;Tape&lt;&#x2F;code&gt;, &lt;code&gt;Cursor&lt;&#x2F;code&gt; and &lt;code&gt;Familiar&lt;&#x2F;code&gt; and I think I’m honing in on the API I want.&lt;&#x2F;p&gt;
&lt;p&gt;I’m essentially dealing with two APIs.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A ‘thing what moves through a file’ API, i.e Cursor&#x2F;Familiar, both of which have file-like APIs to non-file things.&lt;&#x2F;li&gt;
&lt;li&gt;A ‘thing what stores variants of some enum’, i.e., Log or Tape.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;A familiar in particular accrues state as it goes, while a cursor is a ‘stateless’ familiar.&lt;&#x2F;p&gt;
&lt;p&gt;Realistically I don’t care about the #2 thing as much as the #1. #2 is just for storing data and should be ‘pretty dumb’
most of the time, however, I do need to store it somewhere so that I can run my familiar over it to accrue whatever
state it likes. Ultimately a familiar is a type:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Familiar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; F&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Invertible&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    state&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    source&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;a F&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    update&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As the familiar is advanced or retreated, the update function is called with the &lt;code&gt;E&lt;&#x2F;code&gt; (entry) item or it’s inverse if
retreating. The &lt;code&gt;F&lt;&#x2F;code&gt; here is some arbitrary container, I don’t think I can actually specify a type function as a type
parameter but practically that’s a nonissue since this is almost always either &lt;code&gt;Vec&lt;&#x2F;code&gt; (as in &lt;code&gt;Log&lt;&#x2F;code&gt; or a finite array (in
the case of &lt;code&gt;Tape&lt;&#x2F;code&gt;). This parent structure is responsible for updating&#x2F;writing things to the log, the familiar is
responsible for interpreting it’s contents and producing whatever items we like on demand.&lt;&#x2F;p&gt;
&lt;p&gt;I think I want to extend this a bit, since familiars may be ‘left behind’ over time, they are responsible for
incrementally updating themselves. When a cache-out happens (for &lt;code&gt;Tape&lt;&#x2F;code&gt;), their states should also be caught up, cached
off, and put in the ‘initial’ state.&lt;&#x2F;p&gt;
&lt;p&gt;These familiars are initially going to be useful for calculating various zobrist hashes of things for which we can
zobrist. In particular, the &lt;code&gt;Tape&lt;&#x2F;code&gt; backend is made of &lt;code&gt;Alteration&lt;&#x2F;code&gt;s, which ultimately it what implements the zobrist
hashing, so a familiar which is maintaining a hash as I edit the storage makes sense.&lt;&#x2F;p&gt;
&lt;p&gt;Similarly, it makes sense to keep track of the hash at the position of the write head. Since we can just have a Familiar
copy that when the need arises.&lt;&#x2F;p&gt;
&lt;p&gt;I’m just tossing a function pointer in the above, but I suspect that should be some kind of trait. My thought was this
is not really intended to be called outside the context of the familiar, and it’s possible I’ll want to build these
dynamically, especially since these generic familiars will be able to interact with the existing &lt;code&gt;Variation&lt;&#x2F;code&gt; structure
and the &lt;code&gt;Position&lt;&#x2F;code&gt; structure as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>28-FEB-2025</title>
        <published>2025-02-28T00:00:00+00:00</published>
        <updated>2025-02-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/28-feb-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/28-feb-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/28-feb-2025/">&lt;p&gt;Some days, all you can manage is an update to a log.&lt;&#x2F;p&gt;
&lt;p&gt;Dropped those AI subscriptions, I find that &lt;code&gt;qwen&lt;&#x2F;code&gt; on the local P40 is more than enough for my relatively limited LLM
use. Not having &lt;code&gt;Copilot&lt;&#x2F;code&gt; adjacent autocomplete has been a little rough on the hands but ultimately isn’t really costing
time.&lt;&#x2F;p&gt;
&lt;p&gt;I think my next project for the editor is probably to pare down the number of plugins, set up more autocomand&#x2F;language
specific configuration, and continue to improve the ergonomics a bit. I’d like to get all my keybindings centralized and
documented as well, as right now they’re pretty ad hoc from years of accrual.&lt;&#x2F;p&gt;
&lt;p&gt;For the lab, I think the next projects include geting the k3s ‘production’ cluster up and running, and starting to
helmify all my various service-level stuff. That gets me a good balance, more ‘permanent’ services can live as full vms
in NixOS, then I can take my smaller services and use either OTS docker containers or DIY nix-based containers. K8s can
handle distributing across multiple machines.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally I want to build in autoscaling&#x2F;migration, so that my projects are run in a container on my ‘main’ development
machine w&#x2F; remote storage backing them. In the evening when I finish working, I want those containers to migrate
(without losing any internal state) to a single, low power machine, so that I can shut off all my other machines. Then
in the morning I can have them automatically scale up a bit before I need them.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is that – during peak hours of the day I want to have the full horsepower available, but once the family is
asleep I don’t need most of the services running at all. I should be able to turn off a good chunk of the infrastructure
so that I’m only using it when I’m generating the maximum from my solar roof. Combined with a off-grid battery system
and I think it should be possible to get all the horsepower I want out of the 730s as compile-farm machines, while more
or less not using any grid-power for them.&lt;&#x2F;p&gt;
&lt;p&gt;Dare to dream.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, it’s a rough day here, hopefully it’s better for you.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-FEB-2025</title>
        <published>2025-02-27T00:00:00+00:00</published>
        <updated>2025-02-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/27-feb-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/27-feb-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/27-feb-2025/">&lt;h2 id=&quot;0017-atm&quot;&gt;0017 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;My initial idea was to build something like the &lt;code&gt;Cursor&lt;&#x2F;code&gt; struct with &lt;code&gt;ATM&lt;&#x2F;code&gt;, and have a sort of type-agnostic cache, that
I could then have each method use. The cache would be transparent to the caller, you ask for the board, you get it, if
it’s cached you pull it from there, if it’s not you build it right then and cache it. More like memoization&#x2F;transparent
caching.&lt;&#x2F;p&gt;
&lt;p&gt;That’s not a great way to do this, with &lt;code&gt;make&lt;&#x2F;code&gt; and &lt;code&gt;unmake&lt;&#x2F;code&gt; in particular, I have a lot of opportunity for incremental
updates and minimizing halfply-to-halfply work, so it makes sense to do opportunistic caching during this process, and
manage when cache is updated more directly.&lt;&#x2F;p&gt;
&lt;p&gt;Right now that cache is a HashMap, but there are smarter structures for this, and memory will be a concern quickly if I
keep all positions.&lt;&#x2F;p&gt;
&lt;p&gt;So I’ve opted for a much simpler global cache, centralizing all the cache logic in &lt;code&gt;Position&lt;&#x2F;code&gt; for now. Ideally the
eventual model will be something like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Position&lt;&#x2F;code&gt; provides an API to talk about the position, it builds it’s methods out of methods provided by
&lt;code&gt;PositionInner&lt;&#x2F;code&gt;. It provides the pleasant API for implementing, e.g., movegen.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;PositionInner&lt;&#x2F;code&gt; provides the bitboard caclulation and has more memoization-adjacent caching via RwLocked bitboards,
I’ll probably build some custom wrapper around bitboard for that, not sure. Ideally most of the math gets pushed back
here, and this can be a site for optimization of board querys.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;code&gt;PositionInner&lt;&#x2F;code&gt; should ultimately ideally be &lt;code&gt;Copy&lt;&#x2F;code&gt;, just a big pile of bitboards and the like.&lt;&#x2F;p&gt;
&lt;p&gt;I currently have the Alteration cached there as well, but I think I’d prefer that to be first-class on Position, since
most of my incremental opportunities involve tooling around a Log of Alterations.&lt;&#x2F;p&gt;
&lt;p&gt;To wit, another thing I’ve been sorely missing has been a good structure for a collection of alterations, and I realized
as I was writing this that I have the perfect thing already built, that little &lt;code&gt;Log&lt;&#x2F;code&gt; structure backing &lt;code&gt;Variation&lt;&#x2F;code&gt; would
work perfectly here, and it’s &lt;code&gt;transaction&lt;&#x2F;code&gt; feature (which is moreso named for it’s aspiration than it’s actuality) may
see some use.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I’m pretty sure &lt;code&gt;ChessGame&lt;&#x2F;code&gt; is going to get factored away and replaced with &lt;code&gt;Position&lt;&#x2F;code&gt;, and I think that will
net out to a much nicer flow than is currently there.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2354-atm&quot;&gt;2354 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;make&#x2F;unmake is such a drag, but I think the issue may be on the side of the &lt;code&gt;cached_alterations&lt;&#x2F;code&gt; (and more general
alteration system). I’m currently just using a &lt;code&gt;Vec&lt;&#x2F;code&gt;, but it makes sense to have something closer to &lt;code&gt;Log&lt;&#x2F;code&gt;, except I
don’t want all the transaction stuff. Log initially was intended for branching trees of moves, this is something a bit
simpler, and probably finite&#x2F;ring-buffer-ish.&lt;&#x2F;p&gt;
&lt;p&gt;I also sort of want to change how metadata is tracked, right now I have to &lt;code&gt;Assert&lt;&#x2F;code&gt; the whole metadata into the
alteration stream (though technically it shouldn’t be needed), ideally I would only flag when events happen that alter
the metadata state; that would also make it easier to unwind (since I just update the &lt;code&gt;PositionMetadata&lt;&#x2F;code&gt; incrementally),
but it unifies the whole system. This also makes zobrist-ing these guys pretty easy (and very amenable to SIMD
calculation of the zobrist later).&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately what I want to do when doing &lt;code&gt;make&#x2F;unmake&lt;&#x2F;code&gt; is something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;make(mov):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    push the move onto the stack&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    compile the move to alterations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apply each alteration to the zobrist of this position.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    check cache:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if hit, load the contents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if miss,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            use current contents and incrementally update the position,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            populate the cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;unmake:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    unwind alterations until and including the previous START_TURN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        apply each alteration to update the zobrist of the position&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pop the move off the list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    check cache for this position&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if hit, copy contents.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if miss, populate the cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In both cases, the &lt;code&gt;Move&lt;&#x2F;code&gt; is more of a convenience representation for the less compact but much simpler &lt;code&gt;Alteration&lt;&#x2F;code&gt;,
which specifies how to update specific squares, and how metadata updates. In the current model I just dump all 4 bytes
of &lt;code&gt;PositionMetadata&lt;&#x2F;code&gt; into the stream, but I’d prefer if things were a bit more incremental. Turns are already counted,
but I need flags for at least:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Losing Castle Rights (4 bits)&lt;&#x2F;li&gt;
&lt;li&gt;Which is the EP file (if any, it’s 3 bits for the file, absence can indicate no EP)&lt;&#x2F;li&gt;
&lt;li&gt;50 move rule reset (1 bit)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;We can calculate movecount and side-to-move from the pre-existing &lt;code&gt;StartTurn&lt;&#x2F;code&gt; variant.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I want to be able to encode this to a bytestream, so it’s handy to keep aligned to bytes. For now they can
just be full variants, but eventually this will be represented as a bytestream that can be stored and gamestates
recovered without any need to rule checking or any more advanced understanding of chess.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally the &lt;code&gt;make&#x2F;unmake&lt;&#x2F;code&gt; will eventually only store partial alteration tapes, especially if they’re finite, when we hit
some threshold we can take the current zobrist (even in the middle of a partially-applied turn) and clear our buffer and
continue. Essentially allowing us to &lt;code&gt;zobrist&lt;&#x2F;code&gt; whole alteration buffers in and out of cache.&lt;&#x2F;p&gt;
&lt;p&gt;The structure I’m using now (a &lt;code&gt;Vec&amp;lt;Alteration&amp;gt;&lt;&#x2F;code&gt;) doesn’t have the ability to seek around, and ultimately I need to seek
through and do something on each alteration, so the whole thing is much more turing-machine than stack machine. The
latter of which is how I’ve been considering it so far, but it’s inconvenient since it’s not a lot of stack bookkeeping
and manually updating state.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Log&lt;&#x2F;code&gt; datastructure is what I want, but I want to tweak how it works. I’m going to calculate two &lt;code&gt;Zobrist&lt;&#x2F;code&gt; values –
one is the current actual position up to a &lt;code&gt;StartTurn&lt;&#x2F;code&gt; marker, this is the ‘real’ zobrist of the legal chess position.
The other is a zobrist of the sum of all instructions in the buffer. When the buffer is filled, this zobrist is used to
cache the state and then clear the cache, that hash is also stored in the tape as the ‘previous’ state, so unwinding is
always possible. This hash can be computed incrementally along with the other hash. Once in cache, it may be possible to
connect hashes together so that more chunks can be served from cache, but I’ve missed my exit.&lt;&#x2F;p&gt;
&lt;p&gt;This &lt;code&gt;Tape&lt;&#x2F;code&gt; structure is really just responsible for managing the alterations, the &lt;code&gt;Position&lt;&#x2F;code&gt; will compile moves to it,
and maintain it’s own cache based on the zobrist it calculates.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>23-FEB-2025</title>
        <published>2025-02-23T00:00:00+00:00</published>
        <updated>2025-02-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/23-feb-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/23-feb-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/23-feb-2025/">&lt;h2 id=&quot;0034-movegen&quot;&gt;0034 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;Hazel once again correctly calculates the number of moves up to depth 3 from the starting position.&lt;&#x2F;p&gt;
&lt;p&gt;She’s still missing a bunch of rules (castling, checking for pins, etc), but the way I break this up is much better now,
and I think it will be much easier to extend. Once I got going I was able to whip out most of the generators quite
quickly from the old code.&lt;&#x2F;p&gt;
&lt;p&gt;The generator is &lt;em&gt;extremely&lt;&#x2F;em&gt; slow right now. Well over 3 minutes to fail perft 4. I think the initial fix may be to huck
&lt;code&gt;rayon&lt;&#x2F;code&gt; at it so I can get the accuracy down, but I may do some caching if the mood strikes.&lt;&#x2F;p&gt;
&lt;p&gt;See you on the next branch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1132-atm&quot;&gt;1132 - atm&lt;&#x2F;h2&gt;
&lt;p&gt;Why ATM?&lt;&#x2F;p&gt;
&lt;p&gt;Because it’s all about managing the Cache.&lt;&#x2F;p&gt;
&lt;p&gt;This is going to focus on building some caching into the movegenerator, to hopefully speed us up a bit. I am going to
avoid adding more rule implementation till after I’ve got the caching in place.&lt;&#x2F;p&gt;
&lt;p&gt;The main bit of trickiness is going to be hiding the mutable bits so that &lt;code&gt;Position&lt;&#x2F;code&gt; transparently uses or populates the
cache, while the caller only sees the immutable interface – from their perspective &lt;code&gt;Position&lt;&#x2F;code&gt; is just a data object.&lt;&#x2F;p&gt;
&lt;p&gt;I have a basic idea of how to do this. First, setting up some kind of &lt;code&gt;Zobrist&lt;&#x2F;code&gt; style hashing (or maybe BCH, I have a
lot of reading to do) is obvious. Once I have that it should make the &lt;code&gt;unmake&lt;&#x2F;code&gt; step a lot faster (since it won’t be
recalculating from scratch each time.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not sure if I’m going to try setting up benchmarks just yet, but it would make it a bit easier to measure
improvements. I think for now I can just go with wall time, bringing everything up to, say, &lt;code&gt;perft 5&lt;&#x2F;code&gt; to within a couple
minutes would be ideal.&lt;&#x2F;p&gt;
&lt;p&gt;Once I’ve got something relatively quick, I can finish the implementation for accuracy, then come back to refactor tests
and add proper benchmarks.&lt;&#x2F;p&gt;
&lt;p&gt;The cache itself will live on the MoveGenerator, and &lt;code&gt;Position&lt;&#x2F;code&gt; will have a borrowed reference to the &lt;code&gt;ATM&lt;&#x2F;code&gt;, which
itself has a borrowed, mutable reference to the MoveGen. This &lt;em&gt;immutable&lt;&#x2F;em&gt; reference will centralize all the cache
retrieve&#x2F;populate operations, so that multiple &lt;code&gt;Position&lt;&#x2F;code&gt; instances ask a single &lt;code&gt;ATM&lt;&#x2F;code&gt; for items from the
&lt;code&gt;MoveGenerator&lt;&#x2F;code&gt; cache, and the &lt;code&gt;ATM&lt;&#x2F;code&gt; either populates or retrieves those items for the &lt;code&gt;Position&lt;&#x2F;code&gt;. This &lt;em&gt;should&lt;&#x2F;em&gt; mean
that &lt;code&gt;Position&lt;&#x2F;code&gt; stays this fully immutable looking thing and &lt;code&gt;MoveGenerator&lt;&#x2F;code&gt; does all the mutation over time. Since
&lt;code&gt;MoveGenerator&lt;&#x2F;code&gt; is eventually going to be wrapped up in a &lt;code&gt;Witch&lt;&#x2F;code&gt; and sent off to live on a thread, this means
thread-local cache with an immutable interface for the caller, which would be pretty sweet.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve never tried to do anything like this in Rust, the closest I’ve come is the &lt;code&gt;Cursor&lt;&#x2F;code&gt; stuff on what I’ve come to
think of as my “Log-unstructured-messy-tree” datastructure.&lt;&#x2F;p&gt;
&lt;p&gt;It’s on the list for a rewrite too.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, this is the plan, it remains to see if it survives contact.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-FEB-2025</title>
        <published>2025-02-19T00:00:00+00:00</published>
        <updated>2025-02-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/19-feb-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/19-feb-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/19-feb-2025/">&lt;h2 id=&quot;1027-movegen&quot;&gt;1027 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’ve figured out the right split for the move generator. The &lt;code&gt;Position&lt;&#x2F;code&gt; struct is going to be responsible for
fully representing a position with every useful representation, lazily updated.&lt;&#x2F;p&gt;
&lt;p&gt;A position is modified by a &lt;code&gt;move&lt;&#x2F;code&gt;, which is compiled to &lt;code&gt;alterations&lt;&#x2F;code&gt; and those alterations are tagged with metadata
that allows them to be filtered by different subrepresentations. A good example is when calculating pawn moves.&lt;&#x2F;p&gt;
&lt;p&gt;There are six ways a pawn can move.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Push&lt;&#x2F;li&gt;
&lt;li&gt;Double Push&lt;&#x2F;li&gt;
&lt;li&gt;Capture&lt;&#x2F;li&gt;
&lt;li&gt;Promotion&lt;&#x2F;li&gt;
&lt;li&gt;Capture-Promotion&lt;&#x2F;li&gt;
&lt;li&gt;En Passant&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It makes sense to try to calculate some of these in aggregate via bitboards (you can calculate all the pushes in very
short order by a simple shift of a bitboard representing pawns of a given color, and a second representing all the
blockers on the board). Others (en passant) might be easier in another representation since it’s only ever a few squares
to check.&lt;&#x2F;p&gt;
&lt;p&gt;When describing moves as an alteration, we lose some data about the move, in particular what piece was moving, what
color it was, etc. In order to efficiently create these representations, I want to really just &lt;em&gt;ignore&lt;&#x2F;em&gt; a bunch of the
alterations, in particular I only care about alterations affecting pawns, so I really only need to apply a subset of
those alterations to the representation.&lt;&#x2F;p&gt;
&lt;p&gt;This makes for a pretty efficient way to get bespoke representations for different optimizations. The path is something
like:&lt;&#x2F;p&gt;
&lt;p&gt;Describe a particular subrepresentation of the board, e.g., “Positions of all White Pawns”, turn this into a filter over
the set of alterations, which can then be cached, only updating the representation as new alterations meeting the filter
criteria are encountered &lt;em&gt;and&lt;&#x2F;em&gt; only then when asked.&lt;&#x2F;p&gt;
&lt;p&gt;This scales nicely with the &lt;code&gt;Variation&lt;&#x2F;code&gt; structure, I can attach all the same metadata to the compiled result and just
push a copy of the current representation when encountering a branch.&lt;&#x2F;p&gt;
&lt;p&gt;Once we have the subrepresentation tagged, we can translate the bitboard operations &lt;em&gt;back&lt;&#x2F;em&gt; to the predicates that form
the filter, meaning a more complex representation can – I think – be built incrementally without having to repeat the
underlying bitboard operations.&lt;&#x2F;p&gt;
&lt;p&gt;If that works the way I think it will, it would be pretty cool. If you think of &lt;code&gt;positions of all the pawns&lt;&#x2F;code&gt; and
&lt;code&gt;positions of all the white pieces&lt;&#x2F;code&gt; as two subrepresentations, we would find the alterations for the first by searching
for any alteration involving any pawn. When a pawn is captured by a knight, the &lt;code&gt;remove&lt;&#x2F;code&gt; alteration would be tagged &lt;code&gt;pawn&lt;&#x2F;code&gt; because
of the capture, but the &lt;code&gt;place&lt;&#x2F;code&gt; alteration would not be. Similarly, the second would be searching for any alteration
involving any white piece. A move would have it’s place&#x2F;remove both tagged by the source color, on a capture the remove
would be tagged with &lt;em&gt;both&lt;&#x2F;em&gt; colors.&lt;&#x2F;p&gt;
&lt;p&gt;When combining these bitboards, we might &lt;code&gt;pawn_locs &amp;amp; white_locs&lt;&#x2F;code&gt;, but logically this is the same as combining the above
two predicates to look for any alteration tagged both &lt;em&gt;white&lt;&#x2F;em&gt; and &lt;em&gt;pawn&lt;&#x2F;em&gt;. This will result in fewer total alterations,
and so &lt;em&gt;should&lt;&#x2F;em&gt; be faster than either of the constituents.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Position&lt;&#x2F;code&gt; can then start to choose which caches it wants to keep, trying to minimize the amount of work it has to do to
answer all the incoming queries.&lt;&#x2F;p&gt;
&lt;p&gt;The path to this I think is something like:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Build ad-hoc representations in Position’s impl. These won’t do any of this caching, they’ll just build a set of
representations worth using.&lt;&#x2F;li&gt;
&lt;li&gt;Once the movegenerator works, start to extract this Move -&amp;gt; Alteration -&amp;gt; Tagged Alteration -&amp;gt; Cached Alteration
Query idea. Simultaneously set up benchmarks calculating whatever people usually calculate for movegen.&lt;&#x2F;li&gt;
&lt;li&gt;See if this nets out to good performance.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-FEB-2025</title>
        <published>2025-02-19T00:00:00+00:00</published>
        <updated>2025-02-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/19-feb-2025/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/19-feb-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/19-feb-2025/">&lt;p&gt;Nearly deleted a bunch of things, fortunately I had just commited everything off.&lt;&#x2F;p&gt;
&lt;p&gt;Lemony snickets these last few weeks.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>16-JAN-2025</title>
        <published>2025-01-16T00:00:00+00:00</published>
        <updated>2025-01-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/16-jan-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/16-jan-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/16-jan-2025/">&lt;h2 id=&quot;1118-movegen&quot;&gt;1118 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;The irony is that I kinda need this tool for the ruby stuff as well now, hard to keep track of &lt;em&gt;it’s&lt;&#x2F;em&gt; structure.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not gonna do that though. I think I can get this close enough to unblock my movegen work, then I definitely need to
rethink how to do this in Rust instead of Ruby, the way I have the Ruby structured is ‘right’ I think, so it should just
be a port to Rust.&lt;&#x2F;p&gt;
&lt;p&gt;I want to look at the &lt;code&gt;syn&lt;&#x2F;code&gt; crate over &lt;code&gt;treesitter&lt;&#x2F;code&gt;, as well. I have a feeling it’s not going to work the way I want,
because I still want to be able to generate diagrams even for incorrect&#x2F;invalid syntax when possible, but it’s
definitely worth a peek.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>15-JAN-2025</title>
        <published>2025-01-15T00:00:00+00:00</published>
        <updated>2025-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/15-jan-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/15-jan-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/15-jan-2025/">&lt;h2 id=&quot;1111-movegen&quot;&gt;1111 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;Made a lot of progress on the ruby&#x2F;treesitter stuff, and integrated &lt;code&gt;PlantUML&lt;&#x2F;code&gt; which I really like so far. I think I’m
at the point where I need to start treating it as it’s own thing, but it’s still very tied to this project, so I’m not
sure I want to move it out of the repo yet. I also have a long-term plan to make &lt;code&gt;hazel&lt;&#x2F;code&gt; a multi-crate thing, in
particular the &lt;code&gt;ui&lt;&#x2F;code&gt;, the &lt;code&gt;types&lt;&#x2F;code&gt; and this ruby thing (which lacks a name) should all be separate projects, but probably
under the same git repo? Not sure.&lt;&#x2F;p&gt;
&lt;p&gt;I know cargo supports this OOB, so I’m gonna take some time soon and work on a prototype of this, but I think the crate
split is probably after movegen is done.&lt;&#x2F;p&gt;
&lt;p&gt;Right now I can generate some UML ‘cards’ for each of the ADTs in the repo (more or less), there is still some missing
information here and there, but the concept is working alright and it’s mostly about marshalling things to my internal
representation.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;would&lt;&#x2F;em&gt; like to rewrite a bunch of this in Rust at some point, the ruby is quite slow, but I definitely want to get it
producing a diagram with at least all the cards, and maybe adding some relationships where it makes sense.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1456-movegen&quot;&gt;1456 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;Two steps back, one step forward on the UML thing, I broke it up, started refactoring to support grabbing fields, and
ended up turning a bunch of things off in the meantime. I think I’m getting pretty close to the ‘just extract it’ and
maybe even the ‘riir’ phase of this thing, but for now I’m just going to keep chipping away at it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>11-JAN-2025</title>
        <published>2025-01-11T00:00:00+00:00</published>
        <updated>2025-01-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/11-jan-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/11-jan-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/11-jan-2025/">&lt;h2 id=&quot;2137-movegen&quot;&gt;2137 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;I merged, started on movegen, then immediately began procrastinating.&lt;&#x2F;p&gt;
&lt;p&gt;I roughed in a little script to hook up to &lt;code&gt;tree-sitter&lt;&#x2F;code&gt; for querying across the source. My aim is to build up some
scripts to collect some topological information about the codebase.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, I’m beginning to get close to the point where I don’t have sufficient spare memory to dedicate to this to
hold the whole project in my head, which means my organization is starting to break down. I &lt;em&gt;know&lt;&#x2F;em&gt; there is a tangled
web of redundant representations, and I know &lt;em&gt;sort of&lt;&#x2F;em&gt; where all the wiring goes, but I need to get a lower resolution
view of the codebase to start to untangle it.&lt;&#x2F;p&gt;
&lt;p&gt;My first step is to build up something that can pull out the traits, structs, and enums and all their relevant APIs to
some set of files. I can think of ‘easier’ ways to do this (leveraging docgen, for instance, could get me partly there),
but I’d like to sharpen my &lt;code&gt;tree-sitter&lt;&#x2F;code&gt; tool, and I haven’t written ruby in a while. I’ll also need to have it crawl
the &lt;code&gt;src&lt;&#x2F;code&gt; directory and apply the query to every file and build whatever index file I need.&lt;&#x2F;p&gt;
&lt;p&gt;I figure I can dump the relevant information out to a file, then ideally incrementally update it based on filechange.
From there I’d like to generate some graphics I can use to start show the topology; I spent a good hour or so looking
for an off-the-shelf tool to just do the diagramming, but I can’t stand literally every single tool, and I don’t have
the desk space to do it by hand.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2156-movegen&quot;&gt;2156 - movegen&lt;&#x2F;h2&gt;
&lt;p&gt;Worked a bit and generalized things, I’ll need to build up a little model, but I think it could work pretty well. I
should be able to calculate the relevant module from the file path, since I essentially never have a module nested
without it being a separate file other than for tests.&lt;&#x2F;p&gt;
&lt;p&gt;What works now is a dump of the definition of every struct, enum, and trait, along with it’s path.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally I’ll generate something approximating a UML card for each of these types, then I can figure out how to link it
all together.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>9-JAN-2025</title>
        <published>2025-01-09T00:00:00+00:00</published>
        <updated>2025-01-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/9-jan-2025/"/>
        <id>https://disturbed-circles.com/log/hazel/9-jan-2025/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/9-jan-2025/">&lt;h2 id=&quot;1500-ui&quot;&gt;1500 - ui&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’ve got the headless side of this about where I need it. I still don’t have a movegen or evaluator or anything,
but I should be able to get the UI side of things up and running, then I just want to get things set up so I can run the
tokio-console tool, have tracing go to a log file, and also show up in the UI, and then also be able to take commands
from the UI.&lt;&#x2F;p&gt;
&lt;p&gt;That’s not too much, right?&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I &lt;em&gt;think&lt;&#x2F;em&gt; I might actually merge this once I know CI is good. The UI change is probably a total rewrite,
the structure I used in the last iteration was too broken up, and I should really aim to have more ‘everything in one
bucket’ model to start.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately the UI, STDIO, and Error Log threads should all branch off of &lt;code&gt;WitchHazel&lt;&#x2F;code&gt;, &lt;code&gt;Hazel&lt;&#x2F;code&gt; is the chess side,
&lt;code&gt;Witch&lt;&#x2F;code&gt; is the communication engine, and &lt;code&gt;WitchHazel&lt;&#x2F;code&gt; is the handle that manages all the IO. I should be able to move
the &lt;code&gt;run_with_io&lt;&#x2F;code&gt; code into the &lt;code&gt;WitchHazel&lt;&#x2F;code&gt; type as an associated function, and I can similarly move the UI code there
as well.&lt;&#x2F;p&gt;
&lt;p&gt;I would like to take some time to write up a move generator, if only so I can have it play random chess and actually
‘use’ the engine, but I don’t want to get too distracted from current progress. There is a lot of fleshing out to do of
the &lt;code&gt;WitchHazel&lt;&#x2F;code&gt; stuff, including custom messages for debugging, and also getting some kind way of having messages
allocate resources in various subsystems. One of the things I found is I will definitely want to be able to ‘defer’
messages – so that the main queue is actually just the input stream, and the first step is delineating between, e.g.,
UCI commands to update the engine state, versus Hazel-specific stuff to control what the engine is doing internally.&lt;&#x2F;p&gt;
&lt;p&gt;I suppose this might mean I have a few actors to build, I could have a UCI frontend actor that forwards messages to the
WitchHazel actor. WitchHazel can happily talk to itself, but the UCI actor only has state sufficient for the current UCI
game.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2302-ui&quot;&gt;2302 - ui&lt;&#x2F;h2&gt;
&lt;p&gt;I got distracted. I’m stuck debating how I want to approach the next bit of work. I’m leaning towards movegen, I’ve done
it once, I should be able to port it over relatively quickly. The tools I’ve got in place now make it much nicer to work
with. Getting anything in place gets me closer to a working engine, which was originally my EOY goal.&lt;&#x2F;p&gt;
&lt;p&gt;I do want to rebuild the UI, but I think it’s still going to be flawed until I have a working engine to back it. I
considered building something that would just talk to stockfish, but the point of the UI is to have a backend look into
Hazel, so building against stockfish doesn’t really get me anything.&lt;&#x2F;p&gt;
&lt;p&gt;Building the movegen will necessarily build out the DSL for WitchHazel as well, so I think it’s time to merge this and
go back to procrastinating on UI stuff. This branch has been exceedingly misnamed for it’s entire life, and I think that
might be my favorite thing about it. It’s final act, in fact, was one in which it was ultimately decided that not only
should most of that code be deleted,&lt;&#x2F;p&gt;
&lt;p&gt;but also that I should do it later.&lt;&#x2F;p&gt;
&lt;p&gt;Larry Wall said that the three virtues of the good programmer are Laziness, Impatience, and Hubris. I am a good
programmer.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>30-DEC-2024</title>
        <published>2024-12-30T00:00:00+00:00</published>
        <updated>2024-12-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/30-dec-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/30-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/30-dec-2024/">&lt;h2 id=&quot;2249&quot;&gt;2249&lt;&#x2F;h2&gt;
&lt;p&gt;Working on setting a few things up in &lt;code&gt;glamdring&lt;&#x2F;code&gt;; in particualr I’m working on getting set up on a new terminal
emulator, probably &lt;code&gt;ghostty&lt;&#x2F;code&gt;, though &lt;code&gt;kitty&lt;&#x2F;code&gt; remains in contention. In particular, I figured out (via &lt;code&gt;ghostty&lt;&#x2F;code&gt;) how to
get kitty to work alright with &lt;code&gt;tmux&lt;&#x2F;code&gt; using the same (instructions)[https:&#x2F;&#x2F;ghostty.org&#x2F;docs&#x2F;help&#x2F;terminfo] as
&lt;code&gt;ghostty&lt;&#x2F;code&gt;. That solved the immediate issue with &lt;code&gt;kitty&lt;&#x2F;code&gt; everywhere, but I do like the defaults of &lt;code&gt;ghostty&lt;&#x2F;code&gt; better?&lt;&#x2F;p&gt;
&lt;p&gt;In any case, the main motivation is getting image-in-terminal to work. &lt;code&gt;kitty&lt;&#x2F;code&gt; has the edge there right now, on account
of it working correctly in a nested &lt;code&gt;neovim-with-image.nvim-in-kitty-mode in tmux in kitty&lt;&#x2F;code&gt; situation, which &lt;code&gt;ghostty&lt;&#x2F;code&gt;
presently doesn’t. I want to try the alternate backend for &lt;code&gt;image.nvim&lt;&#x2F;code&gt; to see if it works any better, but I know
&lt;code&gt;kitty&lt;&#x2F;code&gt; already has some existing integration with &lt;code&gt;nix&lt;&#x2F;code&gt; anyway, so it may be the better choice.&lt;&#x2F;p&gt;
&lt;p&gt;I also set up &lt;code&gt;stickybuf&lt;&#x2F;code&gt; and started working on &lt;code&gt;avante&lt;&#x2F;code&gt; integration with a local &lt;code&gt;ollama&lt;&#x2F;code&gt; hosted model; but I have
some networking that needs doing there as well.&lt;&#x2F;p&gt;
&lt;p&gt;Hoping I can drop my ChatGPT and Copilot subscriptions in favor of the self-hosted setup.&lt;&#x2F;p&gt;
&lt;p&gt;I also switched over to &lt;code&gt;lix&lt;&#x2F;code&gt; after getting stung by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nix&#x2F;issues&#x2F;9708&quot;&gt;9708&lt;&#x2F;a&gt;; I don’t know if
I’ll stick with it, but it seems to be a drop in for now.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>28-DEC-2024</title>
        <published>2024-12-28T00:00:00+00:00</published>
        <updated>2024-12-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/28-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/28-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/28-dec-2024/">&lt;h2 id=&quot;1514-ui&quot;&gt;1514 - ui&lt;&#x2F;h2&gt;
&lt;p&gt;As everyone else seems to be doing at TOW, I’m trying out the &lt;code&gt;ghostty&lt;&#x2F;code&gt; terminal emulator; and I have to say, the hype
seems pretty reasonable. Coming from iTerm2, it definitely ‘feels’ faster. I’m not sure if that’s just placebo, but it
feels like it renders at a higher framerate.&lt;&#x2F;p&gt;
&lt;p&gt;The relevance to this project comes down to protocol wrt images-in-the-terminal. &lt;code&gt;ghostty&lt;&#x2F;code&gt; uses the &lt;code&gt;kitty&lt;&#x2F;code&gt; protocol,
iTerm2 uses it’s own. Barring significant issues, I’m already thinking &lt;code&gt;ghostty&lt;&#x2F;code&gt; might win out in at least the near
term. I do want to investigate &lt;code&gt;alacritty&lt;&#x2F;code&gt; for this as well. Depending on how I go, the choice of protocol will be made.
I like iTerm, I’ve been a longterm user, but the fact that &lt;code&gt;ghostty&lt;&#x2F;code&gt; is already well integrated with &lt;code&gt;nix&lt;&#x2F;code&gt; from the repo
up is very appealing.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-DEC-2024</title>
        <published>2024-12-27T00:00:00+00:00</published>
        <updated>2024-12-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/27-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/27-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/27-dec-2024/">&lt;h2 id=&quot;2337-ui&quot;&gt;2337 - ui&lt;&#x2F;h2&gt;
&lt;p&gt;I’m working a bit on the UI and a bit on the game driver itself, I’m thinking I’m going to tear up and rebuild the UI
from scratch. The initial design is a little bit too split up and I think a less layered approach makes sense. It should
really be more like a three layer tree, a collection of forms, containing widgets, which contain widgets.&lt;&#x2F;p&gt;
&lt;p&gt;I’d like to experiment with a image-in-the-terminal API, I think designing the Driver and UI in tandem will help as
well, since I think I want the Driver to ultimately house the UI startup code anyway, because ultimately the main entry
point is going to configure an instance of the driver, and then run it.&lt;&#x2F;p&gt;
&lt;p&gt;That makes it so the Driver is the primary entry point, and everything can ultimately speak it’s little language to
drive whatever it needs to do. This will also make it easier to expose driver internals to the UI, which is it’s main
goal.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally the UI would work by setting up some arbitrary query on the hazel engine and then use the output of that query
to render itself. That would reduce the UI to a &lt;code&gt;Query&lt;&#x2F;code&gt; widget and a bunch of glue widgets that glue different
&lt;code&gt;Query&lt;&#x2F;code&gt;-derived widgets together. &lt;code&gt;Query&lt;&#x2F;code&gt; can then also be used outside the UI to drive the engine in general.&lt;&#x2F;p&gt;
&lt;p&gt;The idea would be that the query specifies a particular state you want the engine to converge on, and then it will
return an iterator of solutions to that query. So a query might be logically “Find the best move after a 6 ply search =
the position at turn 10 for black of the current game.”. The Query widget would then break the query into the ‘command’
part (‘in the position at turn 10 for black of the current game.’) and the ‘constraint’ part (’the best move after a 6
ply search); and it would then create a ‘job’ that the driver would pick up and run based on some scheduler (ideally the
job would contain metadata about what it intends to do so the scheduler can be efficient in how it runs the jobs to save
work).&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately I’m interested more in making &lt;code&gt;hazel&lt;&#x2F;code&gt; good at the statistical analysis of large bodies of chess games, not
so much necessarily an engine that is good at beating you at chess; there’s stockfish for that. I am aiming to build
something closer to a “Chess Machine” that can take a script targeting a simple command&#x2F;query language and then generate
games for further analysis. It should be good enough to play and be a reliable, if weak, engine.&lt;&#x2F;p&gt;
&lt;p&gt;The engine what actually solves the constraint I &lt;em&gt;think&lt;&#x2F;em&gt; might just be a MCTS; I can say with some probability what,
e.g., an evaluation distribution looks like. If I get the itch I do want to take a stab at a home-made NNUE
implementation which would ostensibly give me a very strong eval function, so coupled with some SIMD MCTS I can at least
implement a big subset of what I’m interested in, which is statistical views subject to some clever evaluation function.
That evaluation function can generate richer evaluation structures, and I think it could be interesting to see what kind
of trouble you can get up to with that.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-DEC-2024</title>
        <published>2024-12-20T00:00:00+00:00</published>
        <updated>2024-12-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/20-dec-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/20-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/20-dec-2024/">&lt;h2 id=&quot;1249&quot;&gt;1249&lt;&#x2F;h2&gt;
&lt;p&gt;I went ahead and picked up a SSD for DOP to run it’s OS off of, this should allow me to get moved &lt;em&gt;back&lt;&#x2F;em&gt; over to DOP as
a dev machine, randy will still be used as a dev box, but more for GPU workloads and the like until I get it tuned up.
It’ll probably be getting my test configs set against it as well, etc.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to put the 2070 in DOP as well so there is some GPU horses there, but ultimately I do want to run both DOP and
BTG as hypervisors running off iSCSI for boot. I think that gets me the best of both worlds in terms of keeping the
disks separated from the machines that manage them, and sets me up for a move to a DIY SAN eventually.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>17-DEC-2024</title>
        <published>2024-12-17T00:00:00+00:00</published>
        <updated>2024-12-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/17-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/17-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/17-dec-2024/">&lt;h2 id=&quot;1042-srailimaf&quot;&gt;1042 - srailimaf&lt;&#x2F;h2&gt;
&lt;p&gt;This is idle thoughts about how to break up what’s in &lt;code&gt;hazel&lt;&#x2F;code&gt; rn. I don’t think I want to keep everything in the same
codebase longterm, since large parts of it will become quite static (e.g,. the PGN parser, the UCI parser, etc); and
other parts are really not particularly chess related (the &lt;code&gt;Log&lt;&#x2F;code&gt; type, in particular, and the UI to some extent may be
worth separating, if only for namespace friendliness).&lt;&#x2F;p&gt;
&lt;p&gt;This would leave the core chess functionality in the main &lt;code&gt;hazel&lt;&#x2F;code&gt; crate.&lt;&#x2F;p&gt;
&lt;p&gt;Right now my compile times are fine, couple seconds, maybe a minute or two for a fresh build, but I can see the writing
on the wall. It’s also just getting cluttered in the project, so I’m itching to organize.&lt;&#x2F;p&gt;
&lt;p&gt;I think the &lt;code&gt;Log&lt;&#x2F;code&gt; type is going to be the first out, especially because I expect it will see re-use outside of this
project, and because I have some ideas on how to extend it to be more useful in terms of how it manages the data it
stores. In particular, I want to extend it to dynamically load segments into and out of the log, so that I can store
logs bounded by disk space and not memory. To do this, I’ll need to have the &lt;em&gt;Cursor&lt;&#x2F;em&gt; types be responsible for holding
the Log data in memory, and the main &lt;code&gt;Log&lt;&#x2F;code&gt; type will instead use a &lt;code&gt;WriteHead&lt;&#x2F;code&gt; to write to an abstract log which is
stored in segments on disk. Finally making it all async would be nice, but I’m not sure if this design’ll scale to that.
Probably a single-writer multi-reader would be ‘fine’, or some kind of segment-based locking, IDK.&lt;&#x2F;p&gt;
&lt;p&gt;It’s not a new idea but it’s a very nice one, and it seems like it’d be fun to build.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>15-DEC-2024</title>
        <published>2024-12-15T00:00:00+00:00</published>
        <updated>2024-12-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/15-dec-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/15-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/15-dec-2024/">&lt;h2 id=&quot;0037&quot;&gt;0037&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got things sorted I think. I have a spare 2070 I can use for DOP, I’ll pull a bit of it’s memory (half, 64GB) and
put it in BTG. &lt;code&gt;randy&lt;&#x2F;code&gt; will stay there for doing GPU workloads and running &lt;code&gt;ollama&lt;&#x2F;code&gt; models and the like for selfhosted
copilot. DOP will become my main dev machine again, with 64GB of memory and 2070 to run upstairs to my office. To
simplify things I may get a SSD for DOP, that way I can just directly install nixos on the SSD. It abandons entirely my
netbooting experiment, really, but I think it’s probably the right move – I can revisit netbooting in the future when I
have a more stable environment with all my systems running what I need them to run.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>14-DEC-2024</title>
        <published>2024-12-14T00:00:00+00:00</published>
        <updated>2024-12-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/14-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/14-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/14-dec-2024/">&lt;h2 id=&quot;0049-srailimaf&quot;&gt;0049 - srailimaf&lt;&#x2F;h2&gt;
&lt;p&gt;I’m really not liking how the rewind stuff is coming together, and I think I need to change the approach and think about
how I’m going to use Familiar. Initially I was thinking of it as a being fully bidirectional, but trying to track all
the necessary state is looking very complicated, and trying to pack it inside the class itself is looking tricky.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to keep trying just to see if the additional state calculation needed is really as bad as I think, but I’m
pretty sure it’s going to get out of hand, mostly around variation management.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>12-DEC-2024</title>
        <published>2024-12-12T00:00:00+00:00</published>
        <updated>2024-12-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/12-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/12-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/12-dec-2024/">&lt;h2 id=&quot;0004-srailimaf&quot;&gt;0004 - srailimaf&lt;&#x2F;h2&gt;
&lt;p&gt;Starting in on #2 from above, the first step will be doing some work working on the &lt;code&gt;Unplay&lt;&#x2F;code&gt; side of things and maybe
doing some genericizing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1000-srailimaf&quot;&gt;1000 - srailimaf&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been poking around at some other tools I might want to integrate, and came across &lt;code&gt;insta&lt;&#x2F;code&gt;, which I think would
greatly improve the tests for the UI. More generally, I want to start considering how to refactor the test code. I like
being able to put tests right alongside the code it’s testing, but I think ultimately I’d prefer if the test code were a
little less heavily duplicated.&lt;&#x2F;p&gt;
&lt;p&gt;I found &lt;code&gt;rstest&lt;&#x2F;code&gt; which offers a little extra, and I think I have a plan for how to refactor longterm.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Keep developing using &lt;code&gt;#[test]&lt;&#x2F;code&gt; and the builtin runner along side the source. These are ‘in situ’ unit tests, they
are intended to simply do whatever is necessary to make whatever assertion is intended.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tests&#x2F;unit&#x2F;&lt;&#x2F;code&gt; contains an equivalent folder structure, but uses &lt;code&gt;rstest&lt;&#x2F;code&gt; to run the tests, and is more heavily
factored and intended to be the place where &lt;code&gt;in situ&lt;&#x2F;code&gt; tests are moved to once the functionality is stablized (and
really, once I get tired of the long file size).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tests&#x2F;integration&#x2F;&lt;&#x2F;code&gt; can contains integration tests&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tests&#x2F;ui&lt;&#x2F;code&gt; for ui tests via &lt;code&gt;insta&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;and so on.&lt;&#x2F;p&gt;
&lt;p&gt;The goal would be to slowly extract to some generic ‘spec’ – especially for integration tests, relying on
non-hazel-specific tools to implement the test as much as possible will allow for easy cross-comparison with knonw-good
engines. The spec will ideally be engine-agnostic to some extent, so that it should be relatively low maintenance as I
keep tweaking stuff in hazel.&lt;&#x2F;p&gt;
&lt;p&gt;I have some loose refactoring that happens in the unit tests as of right now, and coverage is pretty good, but
integration is a little weak. I’ve been thinking about other metrics that could be useful with respect to coverage, in
particular I’ve been thinking about two in particular:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Lines &#x2F; Test Coverage - How many lines does a particular test touch in our code?&lt;&#x2F;li&gt;
&lt;li&gt;assertions &#x2F; line - How many assertions are made per line of code?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Ideally we want a test to cover as &lt;em&gt;few&lt;&#x2F;em&gt; lines as possible (tests should be precise), while making as many (good)
assertions as possible per line. The former is probably easy to calculate based on the .lcov information, but the latter
is a little trickier. I suspect that these are the underlying metrics that &lt;code&gt;mutant&lt;&#x2F;code&gt;-style testing reveals. Having a high
assertion-per-line ratio would mean that random changes to code are more likely to be caught by &lt;em&gt;some&lt;&#x2F;em&gt; test, reducing
the class of ‘tests-missing-obvious-logic-error’ mutant, but not the ‘subtle-logical-change’ mutant. The latter is far
more rare than the former. Fewer lines touched per test means that the test is making more targeted assertions, which
should address the latter.&lt;&#x2F;p&gt;
&lt;p&gt;I may take a sidequest at some point to investigate how to calculate these metrics, if nothing else than because I like
a good metric.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>11-DEC-2024</title>
        <published>2024-12-11T00:00:00+00:00</published>
        <updated>2024-12-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/11-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/11-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/11-dec-2024/">&lt;h2 id=&quot;0047-familiars&quot;&gt;0047 - familiars&lt;&#x2F;h2&gt;
&lt;p&gt;I am, gods help me, thinking about changing some names again. I think I’m starting to see that I really should try to
pack the metadata in the ‘alterations’ stream. I rejected it because it kept alterations &lt;em&gt;very&lt;&#x2F;em&gt; simple, but I think I
need to allow for some kind of arbitrary metadata encoding that would record ‘events’ that alter some metadata flag,
this would make it easy to undo and track metadata state, at the cost of making the alterations a little more
complicated.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t think I’m going to chase this rabbit &lt;em&gt;yet&lt;&#x2F;em&gt;, but I am not loving how my current design is managing metadata –
which is to say, it’s not really, it’s just assuming partial representations will ‘work out’ and shoving metadata into
the right spots in whatever way works. I think my goal is to try to get the thing to be able to represent a full PGN
with variations. My main target for Hazel is high-depth analysis &#x2F; big data, not necessarily chess playing proper, so
once I can do that, I can start to replace the ugly bits with more confidence since I’ll have a test suite to work
against.&lt;&#x2F;p&gt;
&lt;p&gt;The current plan is something like:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Finish PGN parser via the Familiar system&lt;&#x2F;li&gt;
&lt;li&gt;Implement a recalculation-based ‘backwards movement’ system for the Familiar.&lt;&#x2F;li&gt;
&lt;li&gt;Wire the Variation to a UI widget that connects to the boardstate shown in the UI.&lt;&#x2F;li&gt;
&lt;li&gt;Finish implementing UCI protocol&lt;&#x2F;li&gt;
&lt;li&gt;Implement an &lt;em&gt;extremely&lt;&#x2F;em&gt; bad evaluator&#x2F;movegen system that can arguably play chess.&lt;&#x2F;li&gt;
&lt;li&gt;Take a break&lt;&#x2F;li&gt;
&lt;li&gt;Kill every single mutant and get to 100% coverage.&lt;&#x2F;li&gt;
&lt;li&gt;Start to refactor the design to something comfortable.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I’ll chip away at that before getting into evaluators and UI and all that. I have plans for that but I think I’ve
settled on the design and I just need to finish building it so I can get to the polish phase.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2128&quot;&gt;2128&lt;&#x2F;h2&gt;
&lt;p&gt;I merged, finishing #1 from above. I think #2 will require some work on the &lt;code&gt;ChessGame&lt;&#x2F;code&gt; component, I’m pretty unhappy
with how &lt;code&gt;BEN&lt;&#x2F;code&gt; and &lt;code&gt;FEN&lt;&#x2F;code&gt; are sort of scattered around, I would prefer to treat the board rep more abstractly, and this
gets back to the &lt;code&gt;Alter&lt;&#x2F;code&gt; system and what a ‘board representation’ really is. I think it might start to reveal itself as
I start to remove the hard &lt;code&gt;Move&lt;&#x2F;code&gt; and &lt;code&gt;BEN&lt;&#x2F;code&gt; types in Action.&lt;&#x2F;p&gt;
&lt;p&gt;I could approach this in the ‘dumb’ way of replacing ChessGame with a trait that captures it’s current API. This would
at least gather the API into one spot so I could look at it.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I’m just going to start tweaking stuff and see what happens. Can’t overthink if you stay busy breaking
stuff.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-DEC-2024</title>
        <published>2024-12-10T00:00:00+00:00</published>
        <updated>2024-12-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/10-dec-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/10-dec-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/10-dec-2024/">&lt;h2 id=&quot;1314-familiars&quot;&gt;1314 - familiars&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been chipping away at this and I’ve gone for a bit of a tweak, embedding a lot of what was &lt;code&gt;ChessAction&lt;&#x2F;code&gt; into the
Play trait first class. It’s still tied to specific move&#x2F;boardrep types, but I think that’s okay for the moment. I need
the boardrep because I need to support ‘setup’ commands, and obviously I need the movetype, but I dislike how things
work in the current model and would prefer it to be more generic.&lt;&#x2F;p&gt;
&lt;p&gt;The next step is to get &lt;code&gt;Familiar&lt;&#x2F;code&gt; correctly evaluating to arbitrary positions in the variation; once I can do that, I
can start working to extract the type assumptions.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>30-NOV-2024</title>
        <published>2024-11-30T00:00:00+00:00</published>
        <updated>2024-11-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/30-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/30-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/30-nov-2024/">&lt;h2 id=&quot;1049-familiars&quot;&gt;1049 - familiars&lt;&#x2F;h2&gt;
&lt;p&gt;I’m thinking about some reorg. Part of the process of building &lt;code&gt;Familiar&lt;&#x2F;code&gt; has made it clear that what I have is quite
capable of representing pretty generically any kind of abstract perfect information game, and I’d like to preserve that
property and make it more explicit in the organization. I’m thinking of these changes:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;src&#x2F;game&#x2F;&lt;&#x2F;code&gt; tree to have a &lt;code&gt;src&#x2F;game&#x2F;&amp;lt;name of abstract game&amp;gt;&#x2F;&amp;lt;contents here&amp;gt;&lt;&#x2F;code&gt; structure, so I can represent
other games.&lt;&#x2F;li&gt;
&lt;li&gt;Extract the &lt;code&gt;PositionMetadata&lt;&#x2F;code&gt; struct to this new location for the &lt;code&gt;chess&lt;&#x2F;code&gt; subdirectory.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;board&#x2F;interface&lt;&#x2F;code&gt; to the top level.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
Move &lt;code&gt;compiles_to&lt;&#x2F;code&gt; to the interface section, though presently it’s unused and may remain there, I may leave this on a
twig and remove it from the trunk, haven’t decided yet.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;code&gt;Hazel&lt;&#x2F;code&gt; can then have (ideally) a relatively abstract idea of what a game is, and can hopefully lead to some reuse with
some of the scaffolding (e.g., whatever alpha-beta&#x2F;minimax&#x2F;mcts&#x2F;nnue bullshit I come up with) with other games. I’m
thinking primarily for fairychess, but also even something like &lt;code&gt;nim&lt;&#x2F;code&gt; for testing purposes could be handy. &lt;code&gt;nim&lt;&#x2F;code&gt; is an
extremely simple game, so it’s possibly valuable for debugging and testing purposes, remains to be seen.&lt;&#x2F;p&gt;
&lt;p&gt;All of this should also provide a nice place to put a &lt;code&gt;Game&lt;&#x2F;code&gt; structure that can then implement &lt;code&gt;Play&lt;&#x2F;code&gt;, this should be
generic with respect to board representation and metadata representation, but canonically should use the
&lt;code&gt;PositionMetadata&lt;&#x2F;code&gt; struct for metadata, and any &lt;code&gt;Query + Alter&lt;&#x2F;code&gt; capable rep.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1114-familiars&quot;&gt;1114 - familiars&lt;&#x2F;h2&gt;
&lt;p&gt;As of now, all but #2 is done, tests are passing, so time for a big commit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2321-familiars&quot;&gt;2321 - familiars&lt;&#x2F;h2&gt;
&lt;p&gt;I’m working on the last move from above, and I’m thinking of some further tweaks I want to consider.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, I think I’m going to want to build an ‘Index’&#x2F;‘Cache’ system for &lt;code&gt;Log&lt;&#x2F;code&gt;. Eventually I want to be able to
refer to different parts of the log by different criteria. For instance, I might want to search the log for a specific
turn’s position in a specific variation, I need to find the place in the log where that is, and I may want to cache that
position for later use, so I’m starting to think of what that might look like. In particular I suspect something like
the &lt;code&gt;familiar&lt;&#x2F;code&gt; system would be used to maintain that index and cache. Ultimately this sort of works as a file format for
a database, and &lt;code&gt;hazel&lt;&#x2F;code&gt; acts as an interface to that database.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-NOV-2024</title>
        <published>2024-11-27T00:00:00+00:00</published>
        <updated>2024-11-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/27-nov-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/27-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/27-nov-2024/">&lt;h2 id=&quot;1214&quot;&gt;1214&lt;&#x2F;h2&gt;
&lt;p&gt;I’m thinking I might move to an iSCSI-based approach for VMs for the near term.&lt;&#x2F;p&gt;
&lt;p&gt;The netboot experiment has been cool, but it’s finicky with total available space and also it’s a really slow process to
rebuild the images. I think I can get a lot of the same benefits (centralized storage, decoupled configuration, etc)
with iSCSI and eventually some kind of overlay system.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to build an iSCSI gold-image that can be cloned. It will have a baseline install of a recent NixOS, and will
be periodically mounted and updated. When creating a new machine, I’ll have scripts that:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;COW Clone this iSCSI base image&lt;&#x2F;li&gt;
&lt;li&gt;Create a new RW iSCSI disk&lt;&#x2F;li&gt;
&lt;li&gt;Configure these disks for the new machine.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The machine would then mount the two disks in an overlay, booting form the base COW clone and then writing to the RW
disk with any subsequent updates.&lt;&#x2F;p&gt;
&lt;p&gt;Machines can be periodically recreated, and any dedicated data can be placed on an independent iSCSI, so the COW clone
is just the common shared underlayment, the RW disk is for machine-specific config, and additional independent disks for
application data.&lt;&#x2F;p&gt;
&lt;p&gt;This will require a lot of automation around iSCSI creation, but for the immediate term I’ll probably just make disks
per machine and install that way, a hard clone of the base image should do it. I’ll serve them out of Nancy and once
it’s working I can work on building a better iSCSI server.&lt;&#x2F;p&gt;
&lt;p&gt;To that end, I think I’m targeting 100GBe Ethernet out of the gate, I considered other protocols, and they may be useful
if I want to split out a backplane for data, but in the short term I’m going to keep it simple and have a single flat
network on 100GBe between all physical components that support it (currently only 3 such machines, but I expect that I
will have a few more in the future, so I’m aiming for something in the 16 port range on the switch).&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately the 100GBe switch will link over a pair of 10GBe links to Condorcet, and then the majority of ‘normal’
machines in the lab will still route through there, but the 100GBe backend will be used for the Racked machines to share
data, the traffic is low enough that a flat network should be fine, and I do want to move to IPv6 eventually anyway, at
which point the routing will be much simpler.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;may&lt;&#x2F;em&gt; start-from-v6 on this project, and use it as a lever to excise v4 from my lab, but tbh I’m not sure it’s worth
it in the short term.&lt;&#x2F;p&gt;
&lt;p&gt;All of this mess brought to you by frustrating issues with my prometheus server not mounting NFS the way I like. Hell of
a lot easier when it just looks like a disk.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1619&quot;&gt;1619&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’m going to start by replacing some of the NFS-as-a-target stuff with iSCSI. NFS is really not the right tool
for what I want, which is a pile of bits that the VM can read&#x2F;write from on it’s own. I can still netboot the machines
but have all the data live in iSCSI volumes. I should be able to extend my existing network-storage code for this, and
I’ll have to manually recreate the luns, but I should be able to query the infra code to generate an appropriate list
for Nancy at least, and then that list can eventually drive a proper iSCSI host.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1940&quot;&gt;1940&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, actual plan:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot; checked=&quot;&quot;&#x2F;&gt;
I’ll create NixOS-24.11 as a LUN in my Synology (Nancy)&lt;&#x2F;li&gt;
&lt;li&gt;[~] I’ll mount this LUN on &lt;code&gt;pinky&lt;&#x2F;code&gt;, my lab VM, and install NixOS 24.11 on it.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
I’ll then clone this LUN to a new LUN, PINKY-24.11-ROOT, and mount it on pinky as its new root disk&lt;&#x2F;li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;&#x2F;&gt;
I’ll alter Pinky’s configuration till it can boot from this iSCSI disk.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;After this, I can recreate the other VMs using this new system, the clones will be RW per machine and full copies (since
COW doesn’t seem straightforward here), but it’ll get the system running and I can work on it from there.&lt;&#x2F;p&gt;
&lt;p&gt;I’m a little ways into the plan above and I don’t expect it’ll take to long to get running.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-NOV-2024</title>
        <published>2024-11-26T00:00:00+00:00</published>
        <updated>2024-11-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/26-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/26-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/26-nov-2024/">&lt;h2 id=&quot;1252-familiars&quot;&gt;1252 - familiars&lt;&#x2F;h2&gt;
&lt;p&gt;Continuing from previous entry, I’m starting to solidify the design of the playing-end of this thing.&lt;&#x2F;p&gt;
&lt;p&gt;I have this setup:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Log is a way to store a sequence of anything, in our case ChessActions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Chess Action supports a notion of &amp;#39;Variation&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The Log lays out it&amp;#39;s contents as single, seekable stream, similar to the File API.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Log can produce a Cursor or WriteHead (mutable cursor) on itself, which can be used to navigate the log.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A Familiar takes a Cursor and calculates some useful values, in particular the current board state and current metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;information.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Familiars are generic, they only care that the type they work over implements `Play`, which itself is a trait that is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;generic over the Rule and Metadata types that govern whatever abstract game they define.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A Familiar can be specialized to a specific representation type to allow for faster&#x2F;more efficient calculation, it might&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;be responsible for caching important results, etc. Most directly, it&amp;#39;s responsible for calculating the current board&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and metadata state.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The final engine will essentially be a Log, a bunch of Familiars that can be created&#x2F;destroyed as needed, and insodoing
I can have multiple representations that can all benefit from intraconversion. Familiars should have a ‘Set Position
with cached state’ option which allows one familiar to transfer it’s state to another; so that a Familiar optimized for
fast scanning can then feed one that’s designed for fast querying, etc.&lt;&#x2F;p&gt;
&lt;p&gt;This also means new representations can be easily compared apples-to-apples with exisitng representations.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>23-NOV-2024</title>
        <published>2024-11-23T00:00:00+00:00</published>
        <updated>2024-11-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/23-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/23-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/23-nov-2024/">&lt;h2 id=&quot;0048-pgn&quot;&gt;0048 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;I added a fixme to mark where I left off, but I’ve managed a lot of progress on this parser. I switched to a different
approach that essentially focused on tokenizing the PGN to a much more convenient representation that was easy to shove
into the Variation structure. I’m only missing a few things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Annotations need to be tokenized so they can be ignored correctly.&lt;&#x2F;li&gt;
&lt;li&gt;Comments similar&lt;&#x2F;li&gt;
&lt;li&gt;Better Section marking, I’m just marking start&#x2F;end of file, the naming is bad, etc.&lt;&#x2F;li&gt;
&lt;li&gt;The current_position calculation for Variation needs to be modified&#x2F;replaced to be able to calculate the position at
the tip of the log.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I think those things get me enough to parse PGNs. It should also be possible to reverse this and generate a sequence of
tokens from a variation, which would make it very useful for comparing game trees and the like later on, also handy for
the UI.&lt;&#x2F;p&gt;
&lt;p&gt;I’m currently ignoring the turn marker, but embedding that in the variation could be a pretty handy way to track
different positions within the tree. I want to look into having a sort of ‘detached’ cursor that could be used to have
multiple referents to a single Variation, I think this will be helpful in lots of ways but it starts to venture into
bits of the borrow checker I’ve largely avoided.&lt;&#x2F;p&gt;
&lt;p&gt;Sounds like a problem for future me though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1116-pgn&quot;&gt;1116 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;Finished the annotations and comments from above.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2309-pgn&quot;&gt;2309 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;I need to work a lot on how I navigate around the log.&lt;&#x2F;p&gt;
&lt;p&gt;There is a case, I think, for a specialized cursor that acts as a state machine over the log, that is where the game
tracking lives, a single log can have multiple cursors, which can be constantly growing and being pruned as the engine
works. It tweaks my design a little, but I think that’s the next natural place to put effort. I think the parser is
properly handling PGNs now, so it’s really ‘done’ and should be merged, the conversion to a variation is what’s broken,
but it’s separate from the ‘current_position’ problem that I think this will solve.&lt;&#x2F;p&gt;
&lt;p&gt;I also want to consider embedding the number of moves contained in a variation as part of the variation itself. This
would have to be done in a second pass after tokenization, but it would make the skip-ahead logic much easier.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to split this work into a new branch, then kill mutants until I can merge &lt;code&gt;pgn&lt;&#x2F;code&gt;. The tests for the actual
&lt;code&gt;pgn&lt;&#x2F;code&gt; class will be lacking, but I think I’ll just have to make it up elsewhere.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-NOV-2024</title>
        <published>2024-11-20T00:00:00+00:00</published>
        <updated>2024-11-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/20-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/20-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/20-nov-2024/">&lt;h2 id=&quot;1141-pgn&quot;&gt;1141 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;Having thought about it more overnight, I think my plan is thus:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Get the existing PGN parser to the closest thing to a working state as I can. Hack as needed&lt;&#x2F;li&gt;
&lt;li&gt;Merge&lt;&#x2F;li&gt;
&lt;li&gt;Extract and unify this ‘minilanguage’ thing I have going on into it’s own abstraction (preparing for eventual parser
writing for the Witchlang)&lt;&#x2F;li&gt;
&lt;li&gt;Build a better MoveGen system based on the enum-based approach&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Ultimately Hazel (the engine bit) is going to have a &lt;code&gt;WitchLang&lt;&#x2F;code&gt;, which compiles to &lt;code&gt;WitchASM&lt;&#x2F;code&gt;, which is an Enum-y
language like what I have now. WitchLang will be a small scripting language that can be used to create more complex
queries that can then be optimized, similar to how a database query-plans.&lt;&#x2F;p&gt;
&lt;p&gt;Hazel (the engine) will be a small VM with some tools to alter it’s scale, what represnetations are active, etc. It will
produce a stream of instructions to configure itself and solve any presented chess problem.&lt;&#x2F;p&gt;
&lt;p&gt;This will also allow for more asynchronous processing, e.g., the movegen can request a bunch of calculations, but the
engine can batch and cache these things, reach into existing cache, etc – behind the scenes.&lt;&#x2F;p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Get &lt;code&gt;perft&lt;&#x2F;code&gt; working for a few positions, matching stockfish&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This milestone will be the big ‘I’ve got a system working’ moment; since from here it’s just a matter of adding eval and
pruning tools to the results of the movegen. Ideally I’ll be able to express some basic evaluation functions in the
WitchLang and then start looking to extend it to NNUE and the like. Ideally it’s something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Engine Tune:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Set parameters here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Search &amp;lt;Some FEN&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Depth &amp;lt;some plycount&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Prune With:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Some subprogram&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Filter Final:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Some subprogram&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Group By:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Some subprogram&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# etc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gets compiled down to a series of &lt;code&gt;WitchASM&lt;&#x2F;code&gt; instructions that can be run on the engine, and then ideally the
language can express self-retuning as it iterates, etc. Ideally all the chess-related logic ends up in this language and
we then attack the problem like a compiler problem, optimizing to intermediate reps and building an engine that can
solve the given script optimally.&lt;&#x2F;p&gt;
&lt;p&gt;I think this will make for something very flexible, since most of the chess logic will live in the language and not the
engine itself. I suspect I may see some overhead, but I’m hoping the translation layers should mitigate some of that,
since the final set of instructions that the thing needs to execute should be somewhat smaller. Translating further down
to bytecode (and perhaps SIMD bytecode, since most of these operations should be parallelish) should be doable and
hopefully keep the speed sufficient to justify the flexibility on offer.&lt;&#x2F;p&gt;
&lt;p&gt;For Eval, I’m planning to build a bunch of different eval functions, but I’m particularly interested in NNUE and messing
around with different architectures using the NNUE concept. More SIMD in my future.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally I’d like to get to the point where I have a suite of integration tests that:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use WitchLang to load a PGN, do evaluation to it, and report statistics about the results.&lt;&#x2F;li&gt;
&lt;li&gt;Use WitchLang to perft from multiple different positions and compare statically to stockfish&lt;&#x2F;li&gt;
&lt;li&gt;Use WitchLang to generate a random position by playing random moves, then dynamically compare perft results with
stockfish to the maximum depth achievable in a reasonable time.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Those three tests should fully exercise any movegen code I’m using; especially if I can set the number of PGNs pretty
high.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2136-pgn&quot;&gt;2136 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;I ticked off #1 of the above and got past the ambiguity with sliding pieces. I even got to use some of the old bitboard
implementation.&lt;&#x2F;p&gt;
&lt;p&gt;I need to do some work to get variations parsing and the like, but I think the move generation is probably ‘good enough’
that I shouldn’t run into an ambiguity problem again.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not tempting the gods, &lt;em&gt;you’re&lt;&#x2F;em&gt; tempting the gods!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-NOV-2024</title>
        <published>2024-11-19T00:00:00+00:00</published>
        <updated>2024-11-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/19-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/19-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/19-nov-2024/">&lt;h2 id=&quot;2313-pgn&quot;&gt;2313 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;I’m frustrated by the fact that PGN requires, essentially, an entire movegen system to parse. I’m going to hack in
something in the ‘good enough’ category so I can flesh out the Variation stuff and then probably put it down and go to
work on the MoveGen. I have an idea for it that I think will work well with the design I’m aiming for. In a surprise to
no one, it’s copying the &lt;code&gt;Alter&lt;&#x2F;code&gt; system. I’m going to use the old movegen as a guide, and focus on building a system
that can implement a rich language for querying a boardstate. I can then use this to build a movegen system that is
abstract with respect to boardstate &lt;em&gt;and&lt;&#x2F;em&gt; can abstractly describe different movegen calculation strategies that can then
be run against multiple backend boards.&lt;&#x2F;p&gt;
&lt;p&gt;An implementor would then have to implement some minimal set of operations, which all others must be expressed in terms
of, and then I can build different backend representations designed to make some operations faster.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately this will build up to a general language that can describe how to arrive at specific boardstates, and how to
do analysis downstream.&lt;&#x2F;p&gt;
&lt;p&gt;You’d have a script that describes some algorithm to tell the engine how to proceed from it’s current position, what to
evaluate (e.g., maybe “find the top 100 lines from this position for white at depth &lt;code&gt;n&lt;&#x2F;code&gt; and then calculate the relative
power of the black bishop in each lines and report the distribution as a graph”), and then hazel would haul off and do
the work.&lt;&#x2F;p&gt;
&lt;p&gt;Each little language is really a part of this bigger language that ultimately ‘compiles’ to some glue language.&lt;&#x2F;p&gt;
&lt;p&gt;I was hoping to get &lt;code&gt;pgns&lt;&#x2F;code&gt; more fully and comfortably supported, but I don’t think that’s going to be possible right
now. I might still work on the Variation -&amp;gt; PGN (at least the mainline) so I can display it in the UI, but I’ll have to
think about how much I want to keep writing parser&#x2F;printer code.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>15-NOV-2024 - pgn</title>
        <published>2024-11-15T00:00:00+00:00</published>
        <updated>2024-11-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/15-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/15-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/15-nov-2024/">&lt;h2 id=&quot;2157&quot;&gt;2157&lt;&#x2F;h2&gt;
&lt;p&gt;I’m writing the parser, it’s going alright. I’m finding myself in want of a lot of QoL stuff so I’m splitting between them.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, not being able to have a cheap, copy-able board representation like FEN was killing me, so I started
working on BEN, which is a relatively compact binary-encoded FEN equivalent. Insodoing I added &lt;code&gt;Alter&lt;&#x2F;code&gt; to &lt;code&gt;FEN&lt;&#x2F;code&gt; so it
technically counts as a whole Board Representation now. This led me to realize I’ve been using &lt;code&gt;PieceBoard&lt;&#x2F;code&gt; pretty
liberally as a way to make FEN alter-able, and I’ve unwittingly bound it quite tightly to a particular board
representation internally. It occured to me it would be pretty cheap to abstract this to a type alias that only claims
it’s traits and no particular internal representation. So in principle something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Board&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Alter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Query&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Into&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; PieceBoard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I can use &lt;code&gt;Board&lt;&#x2F;code&gt; everywhere, and if I want to switch to a different representation, I can just change the type to
anything that implements the traits. Later I can add additional traits like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveGenOptimizedBoard&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Alter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Query&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Into&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Bitboard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; UIOptimized&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Alter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Default&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Query&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Into&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; CharBoard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I suspect I’ll want to introduce some kind of granularity here, I’m not sure the best way to do it, but I want to rely
on no specific board representation interally, but rather on a set of traits that can be implemented by any board
representation.&lt;&#x2F;p&gt;
&lt;p&gt;I’m premature in my optimization, but I can see that there will be a point where board representation becomes an
optimization path and I want to approach that in a structured way.&lt;&#x2F;p&gt;
&lt;p&gt;I suppose figuring out how to extract the generic &lt;code&gt;Board&lt;&#x2F;code&gt; type is the first step.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2038-pgn&quot;&gt;2038 - pgn&lt;&#x2F;h2&gt;
&lt;p&gt;I’m thinking a bit more about &lt;code&gt;Alteration&lt;&#x2F;code&gt; and what I should encode there. I think ultimately I do want to try to
encode the entire gamestate in the &lt;code&gt;Alteration&lt;&#x2F;code&gt; stream, which means encoding some sense of metadata, as well as game
events, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;Each board representation implementation is going to be good at “something”, it may be optimized for efficient movegen,
or for easy evaluation, etc. I think each &lt;code&gt;Alter&lt;&#x2F;code&gt; type should advertise which subset of the commands it implements.
During ‘compilation’, the ‘compiler’ will check this list and try, where possible, to provide implementations of
whatever keywords are missing. So for instance, if a BoardRep doesn’t implement the ‘Clear’ command, the compiler will
replace it with 64 ‘Remove’ tags, assuming it implements ‘remove’.&lt;&#x2F;p&gt;
&lt;p&gt;As I build up the engine’s abilities, I can add new commands, and so long as I can implement them in terms of the older
commands, I should be able to use the new command with any older board representation still, even if a bit slower. This
matters for the UI and non-engine-y parts of Hazel. Since the UI is a big part of how I plan to develop Hazel, I want to
build the UI to also read along the Log of ChessActions, which ultimately become a list of alterations.&lt;&#x2F;p&gt;
&lt;p&gt;Different consumers of that log stream can maintain a &lt;code&gt;Cursor&lt;&#x2F;code&gt; into the log and then ideally rewind&#x2F;fastforward to any
state in the log. The composed object will implement &lt;code&gt;Alter&lt;&#x2F;code&gt; as the sum of it’s internal implementations, and dispatch
commands to subcomponents as it pleases. So the UI’s implementation of &lt;code&gt;Alter&lt;&#x2F;code&gt; might update it’s UI oriented internal
state, while the Engine might instead be grabbing many alter’s at once and applying them in batches somehow.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-NOV-2024</title>
        <published>2024-11-10T00:00:00+00:00</published>
        <updated>2024-11-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/10-nov-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/10-nov-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/10-nov-2024/">&lt;h2 id=&quot;1219-gamerep&quot;&gt;1219 - gamerep&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got &lt;code&gt;Variation&lt;&#x2F;code&gt; (formerly  Game, Line, HalfPly and Ply… it’s been through a few iterations) basically working.
It can at least represent a simple variation, and while the API is going to need some finishwork, I think the design
works and I should be able to flatten a PGN into it.&lt;&#x2F;p&gt;
&lt;p&gt;I’m debating now between merging and tackling that in a separate PR, or just pushing through and getting it done. I
think I might try to push through and see how painful it is. If it comes together quickly then I’ll go for it, but
otherwise I’ll plan to merge and then tackle it in a separate PR.&lt;&#x2F;p&gt;
&lt;p&gt;I have an existing ‘no-variations’ PGN example I can use, and I think I should probably have the test exist in the
&lt;code&gt;tests&#x2F;&lt;&#x2F;code&gt; subdir as it’s more of an integration test than a unit test. I plan to use the &lt;code&gt;Shakmaty&lt;&#x2F;code&gt; PGN parser for now,
but would like to build my own eventually.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1628-gamerep&quot;&gt;1628 - gamerep&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’m going to merge.&lt;&#x2F;p&gt;
&lt;p&gt;I also think I’m going to write my own parser (probably with &lt;code&gt;nom&lt;&#x2F;code&gt;, maybe fully by hand).&lt;&#x2F;p&gt;
&lt;p&gt;Here’s why.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The next step really is a big change in design, I’m going to be doing parser stuff, it’s not going to be particularly
chess-y, and it &lt;em&gt;should&lt;&#x2F;em&gt; be pretty &lt;em&gt;simple&lt;&#x2F;em&gt; believe it or not.&lt;&#x2F;li&gt;
&lt;li&gt;The model I have and the model the pgn-reader&#x2F;shakmaty use are very different. I &lt;em&gt;should&lt;&#x2F;em&gt; be able to directly read a
variation in a single pass, no visitors or whatever, just a single read to translate each move to the correct format.
The OTS dependencies expect a visitor-pattern approach because they (rightly) believe most people won’t be doing weird
bytecode shit.&lt;&#x2F;li&gt;
&lt;li&gt;Doing it myself means I can drop a couple dependencies, which is very cool.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I’ll probably use &lt;code&gt;nom&lt;&#x2F;code&gt;, but I may even try a simple RD parser myself, since the format is pretty simple. I will
probably build a &lt;code&gt;PGN&lt;&#x2F;code&gt; object that holds all the metadata and the actual variation, which can then be produced by&#x2F;handed
off to the actual Engine.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>31-OCT-2024</title>
        <published>2024-10-31T00:00:00+00:00</published>
        <updated>2024-10-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/31-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/31-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/31-oct-2024/">&lt;h2 id=&quot;2007-gamerep&quot;&gt;2007 - gamerep&lt;&#x2F;h2&gt;
&lt;p&gt;Spooky season is ’pon us, and I have deleted a bunch of code. I’ve been working on the &lt;code&gt;Game&lt;&#x2F;code&gt; representation, and I
think I have the design down (almost)&lt;&#x2F;p&gt;
&lt;p&gt;The main problem, it seems, is metadata. In order to know, for instance, who is allowed to castle, I need to know if any
one of a number of events has occured over the course of the game up to this point. This can be calculated each time I
need it, and it is admittedly not the most expensive thing in the world, but it gets tricky when I need to know the
metadata state in a particular variation of a particular position and it can very rapidly get hairy.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Alter&lt;&#x2F;code&gt; system works really nicely for this, I have an &lt;code&gt;Alteration&lt;&#x2F;code&gt; struct that has much simpler primitive
operations to the board, so I though, “Can I extend this language?” and the answer is “Actually I should just build
another language.”&lt;&#x2F;p&gt;
&lt;p&gt;So now I have &lt;code&gt;ChessRule&lt;&#x2F;code&gt;, which includes the higher level actions that ‘compile’ to this lower level ‘alteration’,
I’ve also added a couple alterations variants. &lt;code&gt;Clear&lt;&#x2F;code&gt; simply instructs the implementor to reset the state of the board
to nothing, and &lt;code&gt;Tag&lt;&#x2F;code&gt; allows a 4 byte ‘tag’ in the output that is otherwise ignored. These allow me to easily generate a
single stream of Alterations that can:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Describe the change to the boardstate over time&lt;&#x2F;li&gt;
&lt;li&gt;Represent arbitrary trees of games&lt;&#x2F;li&gt;
&lt;li&gt;Be easily ‘compressed’ to a ‘compact’ form (distinct from, but equivalent too, FEN) for any single boardstate&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Since &lt;code&gt;Alteration&lt;&#x2F;code&gt;s are reversible (mod Clear, more in a sec), I can easily scroll forward and backward within the space
of a single ‘clear’ call, and if I need to rewind to before that, I just rewind back to the previous clear and rerun.&lt;&#x2F;p&gt;
&lt;p&gt;This leaves the existing &lt;code&gt;Alteration&lt;&#x2F;code&gt; stuff more or less unchanged, and allows me to use this new higher level language
to describe a chess game as a stream of &lt;code&gt;ChessRule&lt;&#x2F;code&gt;s, which can track higher level details. The Game Representation is
just a vector of &lt;code&gt;ChessRule&lt;&#x2F;code&gt; that gets &lt;code&gt;Move&lt;&#x2F;code&gt;s &lt;code&gt;#make&lt;&#x2F;code&gt;d on it, and when the move is made, the representation can also
add any number of metadata variants too, these then get ‘compiled’ in the current context and added to the vector of
&lt;code&gt;Alteration&lt;&#x2F;code&gt;s that then represent the game. The metadata gets added as &lt;code&gt;Tag&lt;&#x2F;code&gt; variants in the GameRep.&lt;&#x2F;p&gt;
&lt;p&gt;All this still requires a bunch of work and testing, in particular getting the &lt;code&gt;Tag&lt;&#x2F;code&gt; parts right is proving a little
tricky. I initially thought of sticking a [u8] slice in the tag, and I still, tbh, want to do that, but it ends up
touching a bunch of the system with lifetime annotations and that seems really lousy.&lt;&#x2F;p&gt;
&lt;p&gt;Current plan is just to power through till I get something that can represent a PGN and get that wired up to the UI,
maybe with some kind of insight from PGN -&amp;gt; ChessRule -&amp;gt; Alteration&lt;&#x2F;p&gt;
&lt;p&gt;A practical effect of this is also that many things currently implementing &lt;code&gt;Engine&lt;&#x2F;code&gt; really shouldn’t, since they can’t
track metadata, which makes a &lt;em&gt;ton&lt;&#x2F;em&gt; of sense in retrospect. I kept trying to figure out how to reconcile why it felt so
weird that any board rep was a kind of ‘engine’, but in this model, they’re not, they’re just &lt;code&gt;Query + Alter&lt;&#x2F;code&gt;,
make and unmake are really part of another trait, &lt;code&gt;Play&lt;&#x2F;code&gt;, which is different than something which can be merely
‘altered’; it implies an understanding and ability to track metadata for the given game. In my case, there is only one,
but I have a &lt;code&gt;Play&lt;&#x2F;code&gt; trait which specifies a particular included type, &lt;code&gt;Rule&lt;&#x2F;code&gt;, which takes the equivalent of the
&lt;code&gt;Alteration&lt;&#x2F;code&gt; struct (in this case, ChessRule) and has an &lt;code&gt;apply&lt;&#x2F;code&gt; and &lt;code&gt;unwind&lt;&#x2F;code&gt; method (and _mut variants) to apply and
… unwind the given ‘Rule’[1] and track the metadata internal to the structure, the trait doesn’t care about the
content or how that metadata is stored, just that it is.&lt;&#x2F;p&gt;
&lt;p&gt;Movegen can then take a state as compiled to &lt;code&gt;Alterations&lt;&#x2F;code&gt;, then start creating whatever moves it likes as &lt;code&gt;ChessRule&lt;&#x2F;code&gt;
variants piled on top, the &lt;code&gt;ChessRule&lt;&#x2F;code&gt; includes the idea of a &lt;code&gt;Variation&lt;&#x2F;code&gt; which is a delimited sequence of moves
branching off from the previous. These can be nested to create arbitrary structures. Seeking to a particular variation
involves simply unwinding from the variation backward until you find a &lt;code&gt;Clear&lt;&#x2F;code&gt;, and then reading back the result.&lt;&#x2F;p&gt;
&lt;p&gt;Now we get back to engines, Engines take UCI commands, &lt;code&gt;Play&lt;&#x2F;code&gt;able objects take &lt;code&gt;ChessRules&lt;&#x2F;code&gt; (or whatever other variant),
our system says every UCI command should translate to some set of &lt;code&gt;ChessRules&lt;&#x2F;code&gt; that can then be compiled to
&lt;code&gt;Alteration&lt;&#x2F;code&gt;s and applied to some &lt;code&gt;Alter + Query&lt;&#x2F;code&gt; object to represent the game. This allows a single representation
which can easily be tracked through, the resulting state can be ‘compressed’ to a &lt;code&gt;Clear&lt;&#x2F;code&gt;, a series of&lt;code&gt;Place&lt;&#x2F;code&gt;
operations, and then a set of &lt;code&gt;Tag&lt;&#x2F;code&gt;s to define the metadata, and this representation is easy to turn into any other
board representation you like. So if you want to use SIMDified bitboards, you just need to tell it how to process the
&lt;code&gt;Alteration&lt;&#x2F;code&gt; stream, and once it is in your domain, how you use that representation is your business. Once you want to
send results back, compile them to &lt;code&gt;Alteration&lt;&#x2F;code&gt; or &lt;code&gt;ChessRule&lt;&#x2F;code&gt;s (or even a mixed stream of them) and send them back.&lt;&#x2F;p&gt;
&lt;p&gt;I think this’ll work well for my purpose, but I do expect I’m adding some amount of overhead compared to a direct
implementation. Fortunately, I should be able to test that later if I like by directly interpreting the &lt;code&gt;ChessRule&lt;&#x2F;code&gt;
without the &lt;code&gt;Alteration&lt;&#x2F;code&gt; layer, and that will give me some sense of how much overhead I’m adding by the extra jump.&lt;&#x2F;p&gt;
&lt;p&gt;[1] Here I’m doing a classic math thing of taking a word with a well known and well-understood meaning and using it in a
way which &lt;em&gt;almost&lt;&#x2F;em&gt; fits that meaning but stretches it just a little past comfort. In normal terms, a ‘rule’ is an
assertion toward obedience. You have a rule that says “Thou shalt X”, and you better be X-ing or else you’re breaking
the rule.&lt;&#x2F;p&gt;
&lt;p&gt;However, rules can also be ‘applied’, as in, “Use L’Hopital’s Rule to solve this limit”. In this case, the rule is an
algorithm or technique or manipulation.&lt;&#x2F;p&gt;
&lt;p&gt;Rules can also be ‘observed’, as in “The rule of law”, where the rule is a principle or standard that is generally
understood to be ‘the way things work’ and is used to guide behavior, though not strictly enforce obedience to some
particular interpretation.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;Hazel&lt;&#x2F;code&gt;, a rule is simple ‘An operation that can be applied to a gamestate’. It’s a little bit of all three, but
really it’s closest analog is an ‘Arrow’ between objects. In the “Category”[2] of all Chess games, where arrows are
game-legality-preserving moves between boardstates, a rule is associated with every one of those arrows.&lt;&#x2F;p&gt;
&lt;p&gt;[2] I don’t actually know if this is a proper category, so maybe it’s just a Graph with some extra steps, but I like to
think of it this way.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-OCT-2024</title>
        <published>2024-10-27T00:00:00+00:00</published>
        <updated>2024-10-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/27-oct-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/27-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/27-oct-2024/">&lt;h2 id=&quot;1109&quot;&gt;1109&lt;&#x2F;h2&gt;
&lt;p&gt;Finished the passthrough setup for randy, next steps are to get BTG set up w&#x2F; the 2070 I have and to run cables from the
rack to my office for HDMI and DP from BTG. Then I can use &lt;code&gt;looking-glass&lt;&#x2F;code&gt; and BTG for near-native performance on the
VMs.&lt;&#x2F;p&gt;
&lt;p&gt;Once these are done I’ll look towards migrating &lt;code&gt;mirzakhani&lt;&#x2F;code&gt; into this model as well; and maybe move it down to the rack
as a result. Then I’ll have two hosts with plenty of GPU horsepower I can eventually MDev up.&lt;&#x2F;p&gt;
&lt;p&gt;I haven’t dug too deeply into the MDev side of things, but from the little I’ve read so far, I’m hoping I can have a
setup which gangs up all these GPUs, less for the gaming side of things (if I have to pull one out of the gang to run
whatever, so be it), but for the compute side it’ll be important. A quick test with &lt;code&gt;hashcat&lt;&#x2F;code&gt; got me 13GHashes&#x2F;s on the
P40 alone. I can’t get it to run on the ‘CPU’ on the VM, since it’s a QEMU vCPU it doesn’t see it as a ‘real’ CPU, but I
suspect 13GHashes&#x2F;s is going to translate to a pretty good rate of speed on Brocard. Assuming I get about the same in
candidates-tested-per-second, it’s 11Y of compute time, but I have good reason to believe it’ll be faster (since MD5 is
compartively more complicated than what I’m doing with brocard) and hopefully I can clear the 2e64 space somewhat more
quickly without having to scale out too much.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>16-OCT-2024</title>
        <published>2024-10-16T00:00:00+00:00</published>
        <updated>2024-10-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/16-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/16-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/16-oct-2024/">&lt;h2 id=&quot;2104&quot;&gt;2104&lt;&#x2F;h2&gt;
&lt;p&gt;I merged it. I got everything working again and I merged it. I was able to delete a ton of old code that wasn’t needed,
and really improve the ergonomics of working in &lt;code&gt;hazel&lt;&#x2F;code&gt;. Now that it’s at least partially done, let me take stock of
where things live and what it cost.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;costs&quot;&gt;Costs:&lt;&#x2F;h3&gt;
&lt;p&gt;I binned the &lt;code&gt;NOTATION_TO_INDEX&lt;&#x2F;code&gt; and related constant lookup tables, and replaced them with a common &lt;code&gt;Square&lt;&#x2F;code&gt; type that
is tucked behind a &lt;code&gt;SquareNotation&lt;&#x2F;code&gt; trait. This leaves a door open to change this later, but for the moment having a
consistent type for referring to squares everywhere, and allowing me to easily convert between rank&#x2F;file&#x2F;index is very
handy. Saves me writing octal constants everywhere, too.&lt;&#x2F;p&gt;
&lt;p&gt;I also deleted, more impactffully, the &lt;code&gt;Game&lt;&#x2F;code&gt; and Ply&lt;code&gt;types, these were trying to do way too much, and I have a better approach in mind. This does mean I gave up my progress towards&lt;&#x2F;code&gt;perft`, but I think I can bet back there in a more
stable configuration and not have to worry about carrying the mess with me.&lt;&#x2F;p&gt;
&lt;p&gt;Two weeks of work, and I’m technically behind where I was, but I think it was worth it.&lt;&#x2F;p&gt;
&lt;p&gt;Oh, and the benchmarks are toast. I changed a lot of the bitboard API and that’s all that really had benchmarks. I’m
going to get the thing fully working and then go back and write benches. Originally I had started this as a reason to
learn &lt;code&gt;criterion&lt;&#x2F;code&gt;, but rapidly I found I was less interested in chasing performance then in the core problem of a chess
engine itself, so it bitrot.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;benefits-and-new-design&quot;&gt;Benefits and new Design&lt;&#x2F;h3&gt;
&lt;p&gt;The main benefit is that this enables moving forward with a new design. The organization is slightly improved. It looks
like this now.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    board&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Board Representation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        interface&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;board reps&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    brain&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Primary Subsystem, manages all the other processes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constants&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Useful _constants_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    coup&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Move related code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rep&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # Move representation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        gen&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # Move Generation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    engine&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # UCI Interface Substystem&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evaluator&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Position Evaluation Subsystem&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    game&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Game State Representation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    notation&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Notation Representation + Conversion to internal canonical formats.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fen&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        uci&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        square&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pgn&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    types&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # General types that don&amp;#39;t fit in other subsystems.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bitboard&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pextboard&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        color.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        direction.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        occupant.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        piece.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ui&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # UI code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        model&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # View Models&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        widgets&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # Widgets&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        app.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    util&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Utility functions and some types&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ultimately, the &lt;code&gt;hazel&lt;&#x2F;code&gt; lib will provide a single tokio process &lt;code&gt;hazel&lt;&#x2F;code&gt; which spawns a ``brain&lt;code&gt;process, which in turn spawns whatever other subsystems it wants according to it&#x27;s configuration. This will include a gamestate represnetaiton, some way to speak UCI, evaluation and movegen, etc. The idea is that&lt;&#x2F;code&gt;brain` can dynamically adjust how it’s set up,
connect with other hazel instances, etc.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;hazel&lt;&#x2F;code&gt; process can also optionally spawn a UI, which will allow deeper insight into the engine state.&lt;&#x2F;p&gt;
&lt;p&gt;Already existing is an ability to wrap other engines, so another subproject here is to build some cross-testing tools as
well.&lt;&#x2F;p&gt;
&lt;p&gt;So the thing looks roughly like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hazel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|               &#x2F;--A- Engine Driver Backend&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|------ Brain --|--A- Move Generator(s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|               |---- Game State&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|               \--A- Evaluator(s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;\------ UI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;Hazel&lt;&#x2F;code&gt; process will be the main entrypoint, and will have a VM+scripting language to control it and the other
processes. This might be custom, for fun, not sure. I might just embed lua or something, like a responsible adult.&lt;&#x2F;p&gt;
&lt;p&gt;The goal would be to have a DSL that can load games, do analysis, process that analysis, etc. Less an engine to beat
other engines, more an engine to study positions efficiently, etc.&lt;&#x2F;p&gt;
&lt;p&gt;The next step is to rebuild the Game Representation, it’s mostly done, but I want to get Move and PGN represented in the
notation module and Move’s abstracted towards the &lt;code&gt;MoveNotation&lt;&#x2F;code&gt; trait similar to what I did for&lt;code&gt;SquareNotation&lt;&#x2F;code&gt;, and
&lt;code&gt;Square&lt;&#x2F;code&gt;. This is already underway as well.&lt;&#x2F;p&gt;
&lt;p&gt;After that, MoveGen and Perft. I still have the old &lt;code&gt;Ply&lt;&#x2F;code&gt; code so I can borrow from it where it makes sense. This is new
territory, I want to build it as a &lt;code&gt;tokio&lt;&#x2F;code&gt; process that speaks over some API. Ultimately I want &lt;code&gt;hazel&lt;&#x2F;code&gt; to be natively
multi-system, so it can run it’s components across any system you like, so building up the engine as a bunch of
independent components is going to be necessary. I’ll probably take that opportunity to scaffold in the whole process,
and also get a diagnostic environment set up.&lt;&#x2F;p&gt;
&lt;p&gt;Somewhere in there I also want to make more progress on the UI.&lt;&#x2F;p&gt;
&lt;p&gt;My plan is to have two worktrees, &lt;code&gt;UI&lt;&#x2F;code&gt; and whatever thing I’’m working on at the time. As I implement stuff, I can keep
chipping at the UI as I go.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>13-OCT-2024</title>
        <published>2024-10-13T00:00:00+00:00</published>
        <updated>2024-10-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/13-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/13-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/13-oct-2024/">&lt;h2 id=&quot;2322-movegen-v2&quot;&gt;2322 - movegen-v2&lt;&#x2F;h2&gt;
&lt;p&gt;A great culling has occurred as I move things towards the unified &lt;code&gt;Square&lt;&#x2F;code&gt; approach to notation. I’ve more or less got
everything lined up, and am just chasing out bugs from the various bits that I tweaked incorrectly to return to
compiling. At time of writing, six failing tests remain.&lt;&#x2F;p&gt;
&lt;p&gt;The approach I took seems alright, though it was tricky in spots. Essentially I have everything rely on an implementor
of &lt;code&gt;SquareNotation&lt;&#x2F;code&gt;, which requires the implementor be capable of converting to a &lt;code&gt;Square&lt;&#x2F;code&gt;, which is a simple newtype
around &lt;code&gt;usize&lt;&#x2F;code&gt; that constrains to &lt;code&gt;0..64&lt;&#x2F;code&gt; and provides some convenient const-time functions for working with it. The
trait wraps and provides those functions for general use, eventually it would be nice to push as much to const-time
evaluation as possible.&lt;&#x2F;p&gt;
&lt;p&gt;This should make it easy to have alternative implementations I can experiment with if I find better represnetaitons
later, and should smooth the cutover should the need arise.&lt;&#x2F;p&gt;
&lt;p&gt;After getting &lt;code&gt;Square&lt;&#x2F;code&gt; setup throughout, I plan to do the same thing with &lt;code&gt;Move&lt;&#x2F;code&gt;, building my current, compact &lt;code&gt;Move&lt;&#x2F;code&gt;
representation into the ‘Default’ &lt;code&gt;MoveNotation&lt;&#x2F;code&gt; implementation, similar to &lt;code&gt;SquareNotation&lt;&#x2F;code&gt; and &lt;code&gt;Square&lt;&#x2F;code&gt;. Also &lt;code&gt;FEN&lt;&#x2F;code&gt;
needs to be factoryed in throughout. Here it will be much more likely that thr trait will be valuable, as there are lots
of different move representation schemes, so by implementing the trait, I can set up a canonical pipeline to convert
between different representations. Something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; convert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; M&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; M&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveNotation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveNotation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Move&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;    N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I don’t think it’s possible to write the more general:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; From&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;N&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt; for&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; M&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; M&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveNotation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveNotation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; N&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; M&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Move&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;        M&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;because of orphan instances, but I think the first is good enough for now. I can always add more implementations later,
and within hazel, it’s most likely that I’ll want to move to &lt;code&gt;Move&lt;&#x2F;code&gt; anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Lots of gruntwork to do, but I think the result will be worth it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>12-OCT-2024</title>
        <published>2024-10-12T00:00:00+00:00</published>
        <updated>2024-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/12-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/12-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/12-oct-2024/">&lt;h2 id=&quot;1500-movegen-v2&quot;&gt;1500 - movegen-v2&lt;&#x2F;h2&gt;
&lt;p&gt;I think I have to commit to the reorg now, but some things have changed which makes the above not &lt;em&gt;quite&lt;&#x2F;em&gt; right. I
started to change it and I think I’m just going to get in and start moving things around on a clean commit of this
branch. After that I think I’m going to merge and go back to working on main. It turns out I’m not so great at sticking
to a single topic on a side project so branching isn’t really what I need to do here, at least not till I’ve cleaned up
some of the tech mess I’ve left for myself.&lt;&#x2F;p&gt;
&lt;p&gt;Next update will hopefully have all that done and I can document it here.&lt;&#x2F;p&gt;
&lt;p&gt;Also on the list is going to be getting &lt;code&gt;mkdocs&lt;&#x2F;code&gt; set up for a wiki, and maybe a local docserver, if only to motivate me
to document more.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>12-OCT-2024</title>
        <published>2024-10-12T00:00:00+00:00</published>
        <updated>2024-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/12-oct-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/12-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/12-oct-2024/">&lt;h2 id=&quot;2157&quot;&gt;2157&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been having an issue on DOP (and BTG, for that matter) where after running an in-place update via &lt;code&gt;just deploy dragon-of-perdition&lt;&#x2F;code&gt;, for instance, it will restart some part of the networking stack and then fail to bring it back up.
Killing my SSH connection and making it a real pain to return to function.&lt;&#x2F;p&gt;
&lt;p&gt;I think this has to do with the silly ‘bond everything’ thing I did, but I like the silly thing so I’ve just gotta
figure out how to fix it and I didn’t want to forget.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1335&quot;&gt;1335&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been doing some work on the the nvim config today, getting DAP set up and generally tuning up the editor, which
I’ve neglected for a bit now while I got used to all the changes I made the last time I was stuck on other things.&lt;&#x2F;p&gt;
&lt;p&gt;I’m thinking I need to adjust all my keybindings to be more consistent and more focused. Right now I manage them poorly,
and there is no mnemonic consistency to them. I do prefix most of them with leader, and I generally have 2 ‘kinds’ of
bindings, &lt;code&gt;&amp;lt;leader&amp;gt;&amp;lt;something&amp;gt;&amp;lt;leader&amp;gt;&lt;&#x2F;code&gt; and &lt;code&gt;&amp;lt;leader&amp;gt;&amp;lt;something&amp;gt;&amp;lt;space&amp;gt;&lt;&#x2F;code&gt;. I can ‘arpeggiate’ these, so I don’t have to
hold them all down (chord), but if I type them quickly, it feels like one ‘action’. I like commands to alternate between
hands, as well, so &lt;code&gt;,l,&lt;&#x2F;code&gt; is bad, because I hit &lt;code&gt;,&lt;&#x2F;code&gt; with my right hand, and then have to hit &lt;code&gt;l&lt;&#x2F;code&gt; with my right as well,
which is uncomfortable.&lt;&#x2F;p&gt;
&lt;p&gt;What I’d like to do is establish two kinds of commands with two separate leader keys. A “Right leads” uses my current
leader and starts and ends on the right side with the leader, a “Left leads” uses a different leader key and starts and
ends on the left hand. The third kind of command would be a ‘double key’ command, like &lt;code&gt;&amp;lt;leftleader&amp;gt;ll&lt;&#x2F;code&gt; or
&lt;code&gt;&amp;lt;rightleader&amp;gt;dd&lt;&#x2F;code&gt;, these need to be reserved for the most common commands, since they are by far the easiest to type so
long as I ensure that the keys are on opposite sides of the keyboard.&lt;&#x2F;p&gt;
&lt;p&gt;The goal is to have commands grouped mnemonically both by letter (i.e., the first letter of the command should be mapped
consistently to some subfunction, so all my telescopes might be &lt;code&gt;&amp;lt;rightleader&amp;gt;t&amp;lt;something&amp;gt;&lt;&#x2F;code&gt; (where &lt;code&gt;&amp;lt;something&amp;gt;&lt;&#x2F;code&gt; might
be several characters), and my Debugger commands file under &lt;code&gt;&amp;lt;rightleader&amp;gt;d&amp;lt;something&amp;gt;&lt;&#x2F;code&gt;. Ideally I &lt;em&gt;also&lt;&#x2F;em&gt; sort command
‘kinds’ by hand, so that, maybe, all the commands for altering editor state (e.g., opening files or whatever) are ‘left
hand’ commands, and all the commands for inspecting the state of the object being edited (e.g., running tests, checking
coverage, etc) are ‘right hand’, not sure how to break that up yet.&lt;&#x2F;p&gt;
&lt;p&gt;This, however, will make it easier to remember commands and build up a little cheatsheet, at the moment I routinely have
to poke through my code to figure out where it all lives.&lt;&#x2F;p&gt;
&lt;p&gt;This should also make it a little easier to build up some library functions for this kind of thing. Something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    rightleader&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lua require(&amp;#39;dap-ui&amp;#39;).toggle()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lua require(&amp;#39;dap&amp;#39;).continue()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lua require(&amp;#39;dap&amp;#39;).step_over()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lua require(&amp;#39;dap&amp;#39;).step_into()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lua require(&amp;#39;dap&amp;#39;).step_out()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lua require(&amp;#39;dap&amp;#39;).toggle_breakpoint()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        f&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Telescope find_files&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Telescope buffers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    leftleader&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        e&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;            x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                modes&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nox&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                action&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;some action&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;        # snip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the value on the RHS of the assignment is a string, it’s interpreted as the &lt;code&gt;action&lt;&#x2F;code&gt; with default mode and all that,
if the value is an attrset, it must be the submodule specifying modes&#x2F;actions&#x2F;etc.&lt;&#x2F;p&gt;
&lt;p&gt;by default, it will assume the command is for &lt;code&gt;nox&lt;&#x2F;code&gt; and that it’s a normal mode command ended with &lt;code&gt;&amp;lt;CR&amp;gt;&lt;&#x2F;code&gt;. I can then
build this object as a nix module, then use it to create the keymap and the cheatsheet. Each plugin can specify it’s own
keybindings locally, which get included conditionally with the plugin.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-OCT-2024</title>
        <published>2024-10-10T00:00:00+00:00</published>
        <updated>2024-10-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/10-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/10-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/10-oct-2024/">&lt;h2 id=&quot;0017-movegen-v2&quot;&gt;0017 - movegen-v2&lt;&#x2F;h2&gt;
&lt;p&gt;Thinking about the &lt;code&gt;Notation&lt;&#x2F;code&gt; idea again. I think there is a different way I can approach it that won’t encounter the
type problems I was having. In particular I can use an associated type to track the format of the notation, so that I
can convert internally between the formats.&lt;&#x2F;p&gt;
&lt;p&gt;Another option is just to have an unassociated family of types with mutual &lt;code&gt;From&lt;&#x2F;code&gt; implementations. One called &lt;code&gt;Index&lt;&#x2F;code&gt;,
one called &lt;code&gt;UCI&lt;&#x2F;code&gt;, and so on, then I can have them all be const impls, and everything in the crate can just use &lt;code&gt;Index&lt;&#x2F;code&gt;,
but with a const &lt;code&gt;into()&lt;&#x2F;code&gt; method which converts to the correct type at compile time?&lt;&#x2F;p&gt;
&lt;p&gt;I truly have no idea if that’ll work, but it makes half sense in my head, and my lack of types for these things is
starting to hurt.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0100-movegen-v2&quot;&gt;0100 - movegen-v2&lt;&#x2F;h2&gt;
&lt;p&gt;I think I have a better plan now.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to reorganize the repo like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    board&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bit&#x2F;         # Implementation of a bitboard-based representation. Not the bitboard type itself.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        piece&#x2F;       # Implementation of a simpler array-of-objects representation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        planned&#x2F;     # ... there may be other representations I put here eventually as well.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mod.rs       # Interface definitions and module stuff, Alter and Query live here.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    notation&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Some kind of notation management object, ideally mostly const-time, as a QoL thing. Much&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # easier to have a consistent way to represent notation, instead of the mix of octal and text and coords.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        index&#x2F;    # Index-based move notation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        uci&#x2F;      # UCI Move notation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        san&#x2F;      # SAN Move notation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fen&#x2F;      # FEN gamestate parsing and generation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pgn&#x2F;      # PGN game history parsing and generation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mod.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    move&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rep&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # This contains various compact move representations, and probably also the `alteration` type and it&amp;#39;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # friends.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        gen&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            # Async Move generator, legality checker, etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    game&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # This tracks the gamestate, it&amp;#39;s home to:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        halfply&#x2F;    # Represents a single move&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        line&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        variation&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mod.rs       # The Game Representation object itself.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        interface.rs # The `Chess` trait goes here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evaluator&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # evaluation here, someday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    brain&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Async Hazel Engine&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    engine&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # UCI interface&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        uci&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        driver&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            stockfish.rs # Wrapper around stockfish, for integration testing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            hazel.rs     # Hazel Engine implementation wrapper (wrapping brain.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mod.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mod.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ui&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        model&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        widgets&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        app.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mod.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    types&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # generic&#x2F;crossfunctional types that are used everywhere.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bitboard&#x2F;  # bitboard type implementation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pextboard&#x2F; # pextboard type implementation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mask&#x2F;      # async process wrapper.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constants&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        # Constants used throughout the program&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s a bit easier to see the structure of the thing that way. The ‘brain’ is the main process that the UI will spawn
and interact with. It will spawn the other components and maintain the engine state. I’d like it to have a little
scripting language&#x2F;VM sort of thing to control it via the UI in richer ways than UCI would allow. Ultimately, like
everything, I want to make it’s parts hotloadable so I can leave it running all the time and just reload the
subcomponents on the fly. Everything must scale to infinite machines, uptime must grow.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not going to do this till I finish the new movegen stuff, which should get all the raw materials above (mod the
evaluator, movegen, and brain bits, I suppose) in place, and then I can start to reorganize and clean up some of the
duplication I have now.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>8-OCT-2024</title>
        <published>2024-10-08T00:00:00+00:00</published>
        <updated>2024-10-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/8-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/8-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/8-oct-2024/">&lt;h2 id=&quot;1827-movegen-v2&quot;&gt;1827 - movegen-v2&lt;&#x2F;h2&gt;
&lt;p&gt;Got some initial work done getting a better game-tracking structure in place (&lt;code&gt;HalfPly&lt;&#x2F;code&gt;) and tying it to the existing
&lt;code&gt;Move&lt;&#x2F;code&gt; struct. I also was able to abstract away a lot of the board rep stuff behind some interfaces.&lt;&#x2F;p&gt;
&lt;p&gt;Remaining is to organize the various &lt;code&gt;move&lt;&#x2F;code&gt; related code and start tearing out the old crappy stuff and building
something better. I briefly took a look in &lt;code&gt;notation-spike&lt;&#x2F;code&gt; at doing some const-time notation stuff, but I’m stymied by
the half-implementation there.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve got plenty to do on this side now that the HalfPly work is done, I can start to build up the &lt;code&gt;Line&lt;&#x2F;code&gt; struct and
build up to something that’ll replace the current &lt;code&gt;Game&lt;&#x2F;code&gt; struct.&lt;&#x2F;p&gt;
&lt;p&gt;Once that’s done, I can start work on a movegen&#x2F;legality checker. I think I want to build this as a collection of
small services, one to generate all moves (no legality checking), a second to check for legality independently, and
later evaluation services that can provide various evaluations, these evaluation tools can be tagged and run
independently to compare them to each other in situ. The main process will spawn a process which has the engine backend
and the some frontend that tracks boardstate, options-per-engine, etc. The main process can then spawn whatever child
processes it likes based on the request from the Engine.&lt;&#x2F;p&gt;
&lt;p&gt;It makes sense in my head, which means it almost certainly won’t make sense anywhee else, but that’s how it always goes.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>8-OCT-2024</title>
        <published>2024-10-08T00:00:00+00:00</published>
        <updated>2024-10-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/8-oct-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/8-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/8-oct-2024/">&lt;h2 id=&quot;2140&quot;&gt;2140&lt;&#x2F;h2&gt;
&lt;p&gt;Full disclosure, I scrapped an old entry that was incoherent, I was jotting down a TODO List and not making a lot of
sense.&lt;&#x2F;p&gt;
&lt;p&gt;I got a P40 installed in BTG, and I’m working on figuring out if I can set it up as an MDEV or if I just need to
passthru to &lt;code&gt;randy&lt;&#x2F;code&gt; and call it. I’m leaning toward the latter. I have a 2080 also hanging around that I’ll install once
the P40 is working. Between these I should have plenty of GPU horsepower to insource my LLM usage and also get a proper
dev VM built for both &lt;code&gt;randy&lt;&#x2F;code&gt; (for normal work) and &lt;code&gt;hardie&lt;&#x2F;code&gt; (for security&#x2F;pentesting).&lt;&#x2F;p&gt;
&lt;p&gt;I’m hoping that if I can get the MDEV set up, I’ll be able to run a few VMs backed by at least the P40, ideally it’s the
main ‘development’ card; and then I can use later hardware for the actual compute task on DOP.&lt;&#x2F;p&gt;
&lt;p&gt;Spricht, DOP is getting set up to work as a development machine right now, the build times on &lt;code&gt;hazel&lt;&#x2F;code&gt; are getting out of
hand and it’s not like DOP is doing anything else right now.&lt;&#x2F;p&gt;
&lt;p&gt;Besides these minor roadblocks (like having no idea how MDEV works), things proceed apace. I’ve been focusing much more
on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jfredett&#x2F;hazel&quot;&gt;hazel&lt;&#x2F;a&gt; recently, so the lab work has slowed. I’m using it as a testbed for some
tools I need to build for &lt;code&gt;brocard&lt;&#x2F;code&gt;. In particular working with &lt;code&gt;ratatui&lt;&#x2F;code&gt; has been pretty fun, and &lt;code&gt;tokio&lt;&#x2F;code&gt; less
terrifying than advertised.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>5-OCT-2024</title>
        <published>2024-10-05T00:00:00+00:00</published>
        <updated>2024-10-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/5-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/5-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/5-oct-2024/">&lt;h2 id=&quot;0015&quot;&gt;0015&lt;&#x2F;h2&gt;
&lt;p&gt;These too:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; EMPTY&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot; &amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; HORIZONTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TOP_LEFT_CORNER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┌&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TOP_RIGHT_CORNER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┐&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; BOTTOM_LEFT_CORNER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;└&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; BOTTOM_RIGHT_CORNER&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┘&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; VERTICAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; CROSS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TEE_RIGHT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TEE_LEFT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TEE_DOWN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TEE_UP&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TRANSPARENT_ROOK&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♖&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TRANSPARENT_KNIGHT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♘&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TRANSPARENT_BISHOP&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♗&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TRANSPARENT_QUEEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♕&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TRANSPARENT_KING&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♔&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; TRANSPARENT_PAWN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; : &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;static str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;They may be useful again someday.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2143&quot;&gt;2143&lt;&#x2F;h2&gt;
&lt;p&gt;I got things cleaned up and merged, I think the board is basically done for now. It’s pointed out a need to extract some
of the UI to configuration, so I can change it more easily. I dislike the unicode pieces a lot, I imagine it’s just the
font I’m using not being particular legible, but I think I want to aim in a direction of sprites rendered using a
terminal image api. This is a little bit trickier, and think my time is better spent elsewhere right now. When I do
that, I’ll spend some time looking at custom font patching as well, as keeping it all text is pretty nice, and I don’t
think it’d be too difficult to make some better looking pieces.&lt;&#x2F;p&gt;
&lt;p&gt;I think next I want to set up an integration test, the goal will be to evaluate some deep &lt;code&gt;perft&lt;&#x2F;code&gt;, and send the games
off to be ‘validated’ by &lt;code&gt;stockfish&lt;&#x2F;code&gt;, ideally in parallel (on both sides).&lt;&#x2F;p&gt;
&lt;p&gt;The idea would require building some better abstractions around &lt;code&gt;Engine&lt;&#x2F;code&gt;s, and would also work towards finishing the
movegen component. I do want to build the &lt;code&gt;Alteration&lt;&#x2F;code&gt; based model; but I think I’m close enough with my initial, naive
approach that it’s worth bringing to completion if I can before starting on the next version.&lt;&#x2F;p&gt;
&lt;p&gt;I do want to get the UI finished soon, but it needs some design review, as the current deeply nested approach is a
little tricky without some distinct ‘main loop’. This should be straightforward to build with &lt;code&gt;tokio&lt;&#x2F;code&gt;, but I need to
take some time to do it.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been working with &lt;code&gt;worktrees&lt;&#x2F;code&gt; recently; and I’m debating just having three branches running so I can switch between
subtasks. It’ll make the &lt;code&gt;LOG&lt;&#x2F;code&gt; a little weird to maintain though – parallel universes. Maybe I’ll start adding the
branch to the entry? It should be a straightforward merge process.&lt;&#x2F;p&gt;
&lt;p&gt;I suppose I’ll know by the next entry.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2201-movegen-v2&quot;&gt;2201 - movegen-v2&lt;&#x2F;h2&gt;
&lt;p&gt;Hi from a worktree. This worktree will track work on the ‘movegen-v2’, which is a new approach to tracking gamestate and
generating moves. I expect this branch to merge once over it’s lifespan. I’m running a few of these worktrees
simultaneously, experimenting with the model, we’ll see if it works.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>4-OCT-2024</title>
        <published>2024-10-04T00:00:00+00:00</published>
        <updated>2024-10-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/4-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/4-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/4-oct-2024/">&lt;h2 id=&quot;2339&quot;&gt;2339&lt;&#x2F;h2&gt;
&lt;p&gt;While working on the UI yesterday and a bit today, I thought I was going to have the opportunity to do some extremely
cursed things with unicode variables and stuff, but alas it was not to be. I did, however, make this at one point:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Table&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┌&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┬&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┐&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♜&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♞&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♝&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♛&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♚&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♝&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♞&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♜&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♟&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♙&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;├&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┼&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┤&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♖&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♘&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♗&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♕&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♔&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♗&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♘&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;♖&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;│&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Row&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;└&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┴&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;─&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;┘&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; Constraint&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;from_maxes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;vec!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;repeat&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;column_spacing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;style&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;    Style&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;bg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;White&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Black&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which is beautiful in both rendering and absolute piss-elegance. I did not want it to go to waste in &#x2F;dev&#x2F;null, so I
have recorded it here.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>3-OCT-2024</title>
        <published>2024-10-03T00:00:00+00:00</published>
        <updated>2024-10-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/3-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/3-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/3-oct-2024/">&lt;h2 id=&quot;2049&quot;&gt;2049&lt;&#x2F;h2&gt;
&lt;p&gt;Working on getting the UI to be ‘reactive’, and my heirarchy is making for a real annoying problem of having to thread
the various bits of state through the UI, it would be convenient but clumsy to have it all in a single object on Hazel,
laying out the UI a little more rigidly there would probably work, I think I could simply render to an internal
‘infinite’ buffer and then grab a XxY view to actually render to the screen.&lt;&#x2F;p&gt;
&lt;p&gt;I think a more elegant way, though, is to make the main UI object an async object and have it run a little message queue
that each widget can listen for events addressed to it on. So the handler would grab the event, parse it based on the
current UI state, and enqueue a message which can be seen by any widget and reacted to. This would allow for each widget
to manage all it’s own internal state, just by subscribing to this message queue. Leaving the object structure to
represent the DOM, essentially.&lt;&#x2F;p&gt;
&lt;p&gt;Did I accidentally re-invent React? I don’t know, just seems logical to me, I’m not a UI programmer.&lt;&#x2F;p&gt;
&lt;p&gt;For the moment I’m just going to eat crow and thread everything through, it’s ugly but it will work.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1-OCT-2024</title>
        <published>2024-10-01T00:00:00+00:00</published>
        <updated>2024-10-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/1-oct-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/1-oct-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/1-oct-2024/">&lt;h2 id=&quot;1739&quot;&gt;1739&lt;&#x2F;h2&gt;
&lt;p&gt;A little idea I had to improve board management.&lt;&#x2F;p&gt;
&lt;p&gt;I want to have a single &lt;code&gt;MoveType&lt;&#x2F;code&gt; that is respected across boards, and to me, that really comes down to that
&lt;code&gt;Alteration&lt;&#x2F;code&gt; idea I used in the &lt;code&gt;Pieceboard&lt;&#x2F;code&gt; type. In particular, I reduced from thinking about a move as a monolithic
enum like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; enum&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    QUIET&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    DOUBLE_PAWN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0001&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    SHORT_CASTLE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0010&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    LONG_CASTLE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0011&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    CAPTURE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    EP_CAPTURE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0101&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    UNUSED_1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0110&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;   &#x2F;&#x2F; NOTE: unused at the moment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; UCI sends moves in a simplified long algebraic notation that simply specifies:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; 1. source square&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; 2. target square&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; 3. promotion piece (if any)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; For Hazel, more is expected of the move metadata, but calculating it requires knowing the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; game state. This value is used to indicate that the move metadata is ambiguous and needs to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; be calculated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F;&#x2F; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    UCI_AMBIGUOUS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b0111&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_KNIGHT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_BISHOP&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1001&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_ROOK&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1010&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_QUEEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1011&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_CAPTURE_KNIGHT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_CAPTURE_BISHOP&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1101&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_CAPTURE_ROOK&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1110&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant&quot;&gt;    PROMOTION_CAPTURE_QUEEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 0b1111&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Coupled with some location information, I can instead think of a move as entirely defined by a series of simpler
&lt;code&gt;Alteration&lt;&#x2F;code&gt;s to the board.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;enum Alteration {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(Location, Color, Piece),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Place(Location, Color, Piece),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Comment(&amp;amp;&amp;#39;static str)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A location is a compact representation of a spot on the board, the Piece is a compact representation of a piece, since
there are 64 squares and 6 possible pieces, and 2 colors, then there these can be tightly packed into a single byte. A
move may be multiple ‘alterations’ e.g., a Capture a black pawn on &lt;code&gt;e4&lt;&#x2F;code&gt; with a Knight by White would be:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Comment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1. Ne4 ...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Remove&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;e4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Black&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Pawn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;   &#x2F;&#x2F; Remove the target piece, the piece metadata here is used for unmoving.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Remove&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;d2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; White&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Knight&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; Remove the source piece from it&amp;#39;s original location.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Place&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;e4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; White&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Knight&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; Place it in it&amp;#39;s new location.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;Comment&lt;&#x2F;code&gt; allows for some clever tricks later. This representation means we can represent the game state as a series
of trivially reversible alterations, and we can use the &lt;code&gt;Comment&lt;&#x2F;code&gt; to act as a checkpoint to know when we’ve unwound
enough. Every board representation can, ultimately, just implement some parser for these alterations, and then we can
decouple make&#x2F;unmake from the board representation entirely. Movegen would query a representation of the board, generate
a bunch of &lt;code&gt;Move&lt;&#x2F;code&gt;s, which can then be ‘compiled’ as alterations.&lt;&#x2F;p&gt;
&lt;p&gt;It also means that internally, the engine can happily keep a couple different representations in various stages of the
game tree depending on what the engine might need for evaluation. It can have a pieceboard rep, perhaps, for doing one
kind of analysis where the pieceboard is convenient, and so long as it is only working on that analysis, it can keep it
up to date to the exclusion of other reps. Similarly, it can roll forward or back as needed.&lt;&#x2F;p&gt;
&lt;p&gt;This also makes it much easier to maintain UI-friendly represnetations that can benefit from the faster internal
representations. We can pick up the list of alterations and apply them unchanged.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately this boils down to a &lt;code&gt;BoardRepresentation&lt;&#x2F;code&gt; trait which looks like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Move&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Alteration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;trait&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BoardRepresentation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; alteration&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Alteration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; unmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;BR&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;board&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; BR&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; alteration&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Alteration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; where&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; BR&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BoardRepresentation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;    board&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;make&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;alteration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;trait&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; MoveGenerator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; Calculate _all_ (not necessarily only legal) forward moves from the current position.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; moves&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Move&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;trait&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; LegalMoveGenerator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; Calculate only legal moves from the current position.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; legal_moves&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Move&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will make it easy to differentiate between UI&#x2F;Non-UI reps (e.g., whether it implements MoveGenerator or
LegalMoveGenerator). Meanwhile, &lt;code&gt;!&lt;&#x2F;code&gt; starts to do some heavy lifting because:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl Not&amp;lt;Alteration&amp;gt; for Alteration {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn not(self) -&amp;gt; Alteration {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        match self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Remove(loc, color, piece) =&amp;gt; Place(loc, color, piece),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Place(loc, color, piece) =&amp;gt; Remove(loc, color, piece),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Comment(c) =&amp;gt; Comment(c),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For completeness, every move type is represented:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Quiet(src, dest):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src_color, src_piece = get(src)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Place(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ShortCastle(color):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if color == White:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(6, White, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(4, White, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(5, White, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(7, White, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(62, Black, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(60, Black, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(61, Black, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(63, Black, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LongCastle(color):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if color == White:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(2, White, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(4, White, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(3, White, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(0, White, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(58, Black, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(60, Black, King)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Place(59, Black, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Remove(56, Black, Rook)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Capture(src, dest):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src_color, src_piece = get(src)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Place(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(src, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EnPassant(src, dest):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src_color, src_piece = get(src)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Place(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, src_color, Pawn)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, !src_color, Pawn)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Promotion(src, dest, piece):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src_color, src_piece = get(src)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Place(dest, src_color, piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PromotionCapture(src, dest, piece):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    src_color, src_piece = get(src)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Place(dest, src_color, piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, src_color, src_piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Remove(dest, !src_color, piece)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These rely on an assumed internal ‘get’ function that retrieves the piece at a location, but I think that’s too low
level to include in the trait, since &lt;code&gt;get&lt;&#x2F;code&gt; might be different depending on context and how you want to implement things.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, this should (I think) make for a bit of an easier make&#x2F;unmake system. It &lt;em&gt;may&lt;&#x2F;em&gt; be possible to make it fully
piece&#x2F;color agnostic, but I haven’t thought it that far through yet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>29-SEP-2024</title>
        <published>2024-09-29T00:00:00+00:00</published>
        <updated>2024-09-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/29-sep-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/29-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/29-sep-2024/">&lt;h2 id=&quot;1014&quot;&gt;1014&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve added a ‘placeholder’ widget so I can work more from the top-down on the UI. I designed a UI in the &lt;code&gt;ui-sketch.md&lt;&#x2F;code&gt;
and I’m going to start working towards that now that I have a concept of what I want things to look like. My hope is
that I can start with the layout of mostly &lt;code&gt;placeholder&lt;&#x2F;code&gt; invokes. The whole layout expects a static size, and eventually
I want the UI to just be a window on a larger, statically rendered ‘infinite canvas’ type of thing.&lt;&#x2F;p&gt;
&lt;p&gt;I should emphasize that I am not a UI&#x2F;UX guy and I’m basically making this up as I go, but I think it’ll be cool.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-SEP-2024</title>
        <published>2024-09-27T00:00:00+00:00</published>
        <updated>2024-09-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/27-sep-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/27-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/27-sep-2024/">&lt;h2 id=&quot;0145&quot;&gt;0145&lt;&#x2F;h2&gt;
&lt;p&gt;I have foolishly stayed up too late working on this, but I’ve got the UI in a good spot. I think I’ve identified the
mistake in my approach, in particular, I’m trying to extract modules&#x2F;structs too early, I should start with state living
on Hazel and extract the widgets I need as methods, then abstract the state away in bigger chunks.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-SEP-2024</title>
        <published>2024-09-26T00:00:00+00:00</published>
        <updated>2024-09-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/26-sep-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/26-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/26-sep-2024/">&lt;h2 id=&quot;2034&quot;&gt;2034&lt;&#x2F;h2&gt;
&lt;p&gt;I set up a &lt;code&gt;mask&lt;&#x2F;code&gt; util object, but this is going to require refactoring &lt;code&gt;Engine&lt;&#x2F;code&gt; before I can use
it. I think I can create a second trait, &lt;code&gt;AsyncEngine&lt;&#x2F;code&gt;, which wraps &lt;code&gt;Engine&lt;&#x2F;code&gt;, allowing for both.&lt;&#x2F;p&gt;
&lt;p&gt;I think I need to switch to only returning messages one at a time, rather than trying to eagerly
read. All this needs to factor into the UI as well, which is going to be a bunch of work as well.&lt;&#x2F;p&gt;
&lt;p&gt;For now, I think I can progress with the blocking version and try to get the UI ‘working’ to some
extent with a stockfish backend. Thus back to the UI I guess. Logging output and text-to-stdin input
next, I think.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>24-SEP-2024</title>
        <published>2024-09-24T00:00:00+00:00</published>
        <updated>2024-09-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/24-sep-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/24-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/24-sep-2024/">&lt;h2 id=&quot;1932&quot;&gt;1932&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got things looking a bit more operational now. I’ve refactored the UI a lot to be more aligned
with the tutorial, and I’ve created a skeleton for the datamodel.&lt;&#x2F;p&gt;
&lt;p&gt;I also refactored some of the terminal handling stuff, and chased some bugs in the stockfish wrapper
implementation.&lt;&#x2F;p&gt;
&lt;p&gt;I started on a &lt;code&gt;mask.rs&lt;&#x2F;code&gt; which is going to supercede that stockfish module and be able to manage any
STDIO&#x2F;unix-y process, which should help with future scaling, but it’s tricky and I’m debating
whether I should just bite the &lt;code&gt;tokio&lt;&#x2F;code&gt; bullet or not.&lt;&#x2F;p&gt;
&lt;p&gt;Next step is to improve things by getting state tracking set up on the Hazel side, since engines
generally don’t have ways to display their boardstate (stockfish being a notable exception).&lt;&#x2F;p&gt;
&lt;p&gt;I think I do have enough now to write a test that tries to ‘play’ random moves (generated by Hazel)
for both sides and tries to see if stockfish and hazel ever disagree (including the PGN used to get
there as well).&lt;&#x2F;p&gt;
&lt;p&gt;I did a little coverage testing and I need to get that automated, so somewhere in here there’s going
to be some github action setup to do.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’m close to mergable, though the UI is total trash, I’d prefer to keep developing on main,
so I’ll probably merge soon, perhaps after taking a detour to chase out that damn en passant bug.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2121&quot;&gt;2121&lt;&#x2F;h2&gt;
&lt;p&gt;I chased down that en passant bug, I believe it was a bad metadata provided in the unmake call, but
probably I should be calculating the ‘correct’ metadata from the ‘unmade’ moves metadata. The whole
&lt;code&gt;Ply&lt;&#x2F;code&gt; struct is pretty cooked, tbh.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, back to &lt;code&gt;main&lt;&#x2F;code&gt; I go.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-SEP-2024</title>
        <published>2024-09-20T00:00:00+00:00</published>
        <updated>2024-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/20-sep-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/20-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/20-sep-2024/">&lt;h2 id=&quot;0104&quot;&gt;0104&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve roughed in the UI model&#x2F;viewmodel layout, and also made a quick ‘driver’ that talks to
stockfish over my UCI protocol implementation. I also set up an implementation of Stockfish’s &lt;code&gt;d&lt;&#x2F;code&gt;
command and more generally I think I’m going to work on building up a UCI+ style implementation for
now, with an eventual goal of supporting multiple distinct protocols and transports.&lt;&#x2F;p&gt;
&lt;p&gt;I’m already seeing the UI side of this being separable, but for the moment I think there is some
benefit to keeping it embedded, in particular for building deep analysis tooling into the engine.&lt;&#x2F;p&gt;
&lt;p&gt;The next step is to start building widgets that query against the &lt;code&gt;RaceControl&lt;&#x2F;code&gt; backend. I want to
try to set up threading early in the UI so I suspect the way the widget is managing state might be
subject to a lot of change.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-SEP-2024</title>
        <published>2024-09-18T00:00:00+00:00</published>
        <updated>2024-09-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/18-sep-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/18-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/18-sep-2024/">&lt;h2 id=&quot;1505&quot;&gt;1505&lt;&#x2F;h2&gt;
&lt;p&gt;Stuck on a work problem, decided to commit off some work here while thinking about it. Several
things are in flight here but I haven’t been back fore a while because I simply can’t bring myself
to work on UI code. I’m procrastinating even now.&lt;&#x2F;p&gt;
&lt;p&gt;I’m debating whether I want a special ‘Hazel’ widget that can bypass the UCI interface, or if I want
to support a sort of UCI+ interface that allows for custom commands to be passed through, so I can
just focus on using an existing UCI interface. I’m probably going to branch off and work on both,
because making decisions is hard.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2-SEP-2024</title>
        <published>2024-09-02T00:00:00+00:00</published>
        <updated>2024-09-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/2-sep-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/2-sep-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/2-sep-2024/">&lt;h2 id=&quot;1355&quot;&gt;1355&lt;&#x2F;h2&gt;
&lt;p&gt;https:&#x2F;&#x2F;nix.dev&#x2F;manual&#x2F;nix&#x2F;2.18&#x2F;advanced-topics&#x2F;distributed-builds.html&lt;&#x2F;p&gt;
&lt;p&gt;I need to set up a builder-file that I can put into the justfile that uses DOP, maybe a VM on BTG,
Archi, Hedges (eventually), and whatever other hardware seems reasonable to use as a builder. I
don’t think I have hyprland set up correctly to use the cache, so I’m stuck compiling. I don’t – in
principle – hate the idea of compiling it, but it is slow and it’d be nice to have it build on the
giant R730 that is otherwise unoccupied.&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;nixos.wiki&#x2F;wiki&#x2F;Distributed_build&lt;&#x2F;p&gt;
&lt;p&gt;That wiki indicates I might be able to specify this in nix directly (rather than through a separate
file), that’d be ideal since I can probably calculate it and have an option set within &lt;code&gt;laurelin&lt;&#x2F;code&gt;
that allows a machine to mark itself as a builder. That’ll move nicely into the &lt;code&gt;gehenna&lt;&#x2F;code&gt; setup&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2107&quot;&gt;2107&lt;&#x2F;h2&gt;
&lt;p&gt;I think I have an idea for how to improve the way I’m handling cross-flake concerns (e.g.,
calculating DNS or scrapeTargets), these should live in a library provided by &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; itself,
it can pass along the other flakes for reference, but otherwise be a ‘normal’ nix library. Then I
can set up a just job to start a repl with this library preloaded; and be able to directly interact
with the library; and additionally I can create a ‘run’ job that takes an argument, evaluates it,
and shows the result, just wrapping the &lt;code&gt;nix-instantiate&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;p&gt;That’ll can be used as plumbing for a nicer CLI tool at some point, but for now it should make it
easier to organize the various scripts that currently just live in the flake.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>31-AUG-2024</title>
        <published>2024-08-31T00:00:00+00:00</published>
        <updated>2024-08-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/31-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/31-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/31-aug-2024/">&lt;h2 id=&quot;2150&quot;&gt;2150&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been working on getting some more exporters set up, and I am finding a ‘next-domino’ problem as
I roll out the &lt;code&gt;ipmi&lt;&#x2F;code&gt; exporter, I need to deploy each machine with the new config, but once I do
that I need to deploy &lt;code&gt;daktylos&lt;&#x2F;code&gt; to update it’s configuration to search. This made me think about
how the eventual ‘real’ methodology rolls out; I want to be able to develop an abstract
configuration of machines such that the configuration will be the same no matter how it is
deployed, so that I can then specify the resources necessary for a machine to play a particular
role, and then separately have code that tries to efficiently deploy it using some configuration
data. Essentially separating design from deployment and creating something like a ‘high level’
terraform.&lt;&#x2F;p&gt;
&lt;p&gt;This problem – knowing what to deploy when some configuration changes – is very similar to the
incremental compilation problem, and I think it’ll be an interesting thing to build strategies for
in the operations context. For now, I just have to remember to deploy them sequentially; I think
once I set up the CI server I’ll add some simple logic to allow me to trigger common build patterns
with flags or something. Ideally I could have some way to specify what parts of the config changing
it cares about, but that’s probably much more complicated.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-AUG-2024</title>
        <published>2024-08-27T00:00:00+00:00</published>
        <updated>2024-08-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/27-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/27-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/27-aug-2024/">&lt;p&gt;I got a bunch of things set up in glamdring over the last couple days, I’m hoping to get my workflow
more contained inside of vim itself, so that ultimately I can more or less obviate the need for tmux
and rely only on a vim server. To this end I added &lt;code&gt;neogit&lt;&#x2F;code&gt; (and &lt;code&gt;gitblame&lt;&#x2F;code&gt;, &lt;code&gt;gitgutter&lt;&#x2F;code&gt;, and
&lt;code&gt;diffview&lt;&#x2F;code&gt; to support it), &lt;code&gt;neotest&lt;&#x2F;code&gt;, and &lt;code&gt;toggleterm&lt;&#x2F;code&gt; to my setup. The quake-style terminal is
perfect for what I need most of the time, and once I sort out a good system for backgrounding
processes from it I shouldn’t really need more than the one anyway. A glance of the help did suggest
it is possible to run a couple independent terminals via the plugin.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>24-AUG-2024</title>
        <published>2024-08-24T00:00:00+00:00</published>
        <updated>2024-08-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/24-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/24-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/24-aug-2024/">&lt;h2 id=&quot;0101&quot;&gt;0101&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;nix-instantiate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; --&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;eval&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;builtins&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;fromJSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;builtins&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;readFile&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;telperion&#x2F;emerald.city&#x2F;configs&#x2F;grafana&#x2F;dashboards&#x2F;system-view.json&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;&amp;#39; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; nixfmt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;nix-instantiate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; --&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;eval&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;let template&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;telperion&#x2F;emerald.city&#x2F;configs&#x2F;grafana&#x2F;dashboards&#x2F;system-view-template.nix&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; builtins&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;toJSON&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;template&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;daklytos&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;are my handy snippets of the day, the former I saw on a discourse answer, for how to quickly convert
json -&amp;gt; nix. I have some grafana dashboards I want to templatize, and the first step is getting them
converted. This made short work. Now I took this simple system dashboard and made it into a
template, I can then rattle off a bunch of basic dashboards for each of my services, and then
specialize them and store the specialized versions in the &lt;code&gt;configs&lt;&#x2F;code&gt; directory of telperion to
override it. &lt;code&gt;daktylos&lt;&#x2F;code&gt; uses a library function from &lt;code&gt;laurelin&lt;&#x2F;code&gt; to invoke the dashboards that are
already stored over there, and I’ll build up some helper functions as it makes sense. Once I’ve got
the initial version built, when I specialize them I can import them back into the repo, and
eventually I’ll set up something automated to push them to their own git repo or something.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-AUG-2024</title>
        <published>2024-08-20T00:00:00+00:00</published>
        <updated>2024-08-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/20-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/20-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/20-aug-2024/">&lt;h2 id=&quot;1738&quot;&gt;1738&lt;&#x2F;h2&gt;
&lt;p&gt;I rigged up vpn routing, but ran into an issue where because the containers now routed through a
VPN, they cannot see my local DNS for local DNS queries. I think it should be possible to bypass
this but I don’t really want to at the moment and the whole setup needs some more significant
refactoring anyway, so for the moment I’m just going to turn it all back off but leave my changes in
place.&lt;&#x2F;p&gt;
&lt;p&gt;All this happens in &lt;code&gt;narya&lt;&#x2F;code&gt;, though, so it’s not really visible to anyone but me. Maybe someday I’ll
open source that bit but for now the mystery shall remain.&lt;&#x2F;p&gt;
&lt;p&gt;Independently and in addition, I stood up &lt;code&gt;daktylos&lt;&#x2F;code&gt; in the &lt;code&gt;emerald.city&lt;&#x2F;code&gt; domain to be the
loki&#x2F;prom server, and wired up exporters for nginx, systemd, and the &lt;code&gt;node&lt;&#x2F;code&gt; exporter. There is
definitely some overlap to unpack for these, and I’m beginning to dislike how fat &lt;code&gt;telperion&lt;&#x2F;code&gt;’s
flake is growing, but I think the plan will be to move the logic to &lt;code&gt;laurelin&lt;&#x2F;code&gt;’s library, then have
a leaner &lt;code&gt;telperion&lt;&#x2F;code&gt; library which does the various calculations. Domains eventually should be
flakes unto themselves, I think, so for the moment that stuff can stay put, but the &lt;code&gt;scrapeTargets&lt;&#x2F;code&gt;
key is definitely in need of refactoring.&lt;&#x2F;p&gt;
&lt;p&gt;I also added additional horsepower to &lt;code&gt;barge&lt;&#x2F;code&gt; while I work on getting things configured, I really
don’t care for the &lt;code&gt;*arr&lt;&#x2F;code&gt; apps, they feel bloated and it’s odd to have them split the way they are,
but there doesn’t seem to be any reasonable alternative out there, so I think I’m stuck with them
for now.&lt;&#x2F;p&gt;
&lt;p&gt;Remaining, I need to get my dev VMs built, and I need to start thinking about NFS mounting the &lt;code&gt;nix&lt;&#x2F;code&gt;
store, the two things are not unrelated, but it is a big job so I might take a break from this for a
bit after I finish the work I’ve got going now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1821&quot;&gt;1821&lt;&#x2F;h2&gt;
&lt;p&gt;I’m exhausted. There are performance issues to chase down, and things to fix, but I’m tired so I’m
going to put this down for a few days, I think.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2049&quot;&gt;2049&lt;&#x2F;h2&gt;
&lt;p&gt;One last thought before I put things down, I suspect the majority of my problem is that barge is
overloaded with IO, network, and cpu intensive tasks. I spent a little time setting up some panels
so I could better diagnose, and this not to say I didn’t see it coming, I think if I split out the
rev-proxy into it’s own VM that’s shared between &lt;code&gt;daktylos&lt;&#x2F;code&gt; and &lt;code&gt;barge&lt;&#x2F;code&gt;, and then split the
torrent&#x2F;vpn component into it’s own VM(s), that should get me much closer to where I want to be. I
also suspect at least some of it has to do with the way networking is setup on BTG; since all the VM
traffic has to go in and out through the same pipe, things are simply not very quick when I’m
saturating said pipe. I may temporarily create a secondary bridge that can be dedicated to the
torrent side.&lt;&#x2F;p&gt;
&lt;p&gt;I also suspect I’ve got the CPUs configured in a poor topology that is confusing things and perhaps
slowing them down a bit. I should also review and ensure all the relevant kernel modules and such
are loaded – I am at least two layers of virtualization deep, I suppose I could also try running
these as containers directly on the host, but I’m inclined to try to get this working (as eventually
I plan to run all this on k8s anyway).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>19-AUG-2024</title>
        <published>2024-08-19T00:00:00+00:00</published>
        <updated>2024-08-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/19-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/19-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/19-aug-2024/">&lt;h2 id=&quot;0006&quot;&gt;0006&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got loki running, promtail modules roughed in, and I just need to get the prometheus exporters
set up the same way. I’ve set them to opt out, since I’d rather have the logs then remain dogmatic
to the ‘explicit-is-better-than-implicit’ principle.&lt;&#x2F;p&gt;
&lt;p&gt;I like how promtail converts the nix code directly to JSON, and I need to steal that for Dashy, as
that gets me exactly what I want, each service can automatically provide a dashy snippet that I can
opt into on a per-dashy-instance basis.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>18-AUG-2024</title>
        <published>2024-08-18T00:00:00+00:00</published>
        <updated>2024-08-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/18-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/18-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/18-aug-2024/">&lt;h2 id=&quot;1013&quot;&gt;1013&lt;&#x2F;h2&gt;
&lt;p&gt;As I work on getting the remaining &lt;code&gt;barge&lt;&#x2F;code&gt; services running, I’m thinking about the CI side of this
and how to keep all these machines updated.&lt;&#x2F;p&gt;
&lt;p&gt;I could set up &lt;code&gt;hydra&lt;&#x2F;code&gt;, but I think that’s overkill for my use right now; it is nice that it’s a
bespoke ‘build nixos images’ kind of tool, but I think I can probably get most of the value with
less setup using some &lt;code&gt;laminar&lt;&#x2F;code&gt; scripts that introspect on the &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; flake; and have it
periodically rebuild each of the &lt;code&gt;canon&lt;&#x2F;code&gt; images as &lt;code&gt;vm&lt;&#x2F;code&gt;s into a centralized nix store, then if the
target machines mount &lt;code&gt;&#x2F;nix&lt;&#x2F;code&gt; over &lt;code&gt;nfs&lt;&#x2F;code&gt; and are otherwise mostly static (i.e., they don’t have any
local OS state stored on whatever disks they may have), then it should be possible to verify the
image in CI, then automatically deploy when those images work alright.&lt;&#x2F;p&gt;
&lt;p&gt;Independently, I need to set up a metrics machine, and I think I’m going to create a second,
dedicated VM for it, and probably just set up the services using the other, ‘just give it a
nixos-config’ style container, more as an experiment than anything else. I should be able to re-use
the definitions in &lt;code&gt;laurelin&lt;&#x2F;code&gt; inside these containers, which would make it easier to ‘promote’ them
to full VMs if I wanted to, which is kind of cool – same configuration in multiple locations.&lt;&#x2F;p&gt;
&lt;p&gt;I’d also like to experiment with &lt;code&gt;microvm.nix&lt;&#x2F;code&gt;, which I’ve read a bit about, and more generally with
microvms.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, I’ve removed &lt;code&gt;elenta&lt;&#x2F;code&gt; for now, as I’m not really doing anything with it and I don’t think
it’ll be necessary for a while. Right now building in place is easier, and working out the
deployment strategy for multiple domains is a problem for future Joe.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>17-AUG-2024</title>
        <published>2024-08-17T00:00:00+00:00</published>
        <updated>2024-08-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/17-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/17-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/17-aug-2024/">&lt;h2 id=&quot;1346&quot;&gt;1346&lt;&#x2F;h2&gt;
&lt;p&gt;Moved dashy to a raw YAML config in the repo, I’d like to next move this to a mashable nix-based one
using the existing nix-&amp;gt;yaml conversion stuff, so I can have various parts of the infra
automatically contribute their dashy configs when dashy is enabled.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    pageInfo&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Emerald.City&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Off to see the wizard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        navLinks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Github&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;jfredett&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;NixOS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;nixos.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Dashy Docs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;dashy.to&#x2F;docs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    # ... snip for other sections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Should translate naturally, then the &lt;code&gt;section&lt;&#x2F;code&gt; section is just an attrset of section-name -&amp;gt; other
config.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>15-AUG-2024</title>
        <published>2024-08-15T00:00:00+00:00</published>
        <updated>2024-08-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/15-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/15-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/15-aug-2024/">&lt;h2 id=&quot;1243&quot;&gt;1243&lt;&#x2F;h2&gt;
&lt;p&gt;Got some stuff reorganized and pushed up. I need to build an installer image I can have &lt;code&gt;randy&lt;&#x2F;code&gt; boot
off of, so I can install on the ‘real’ disk and get to something functional, I also need to set up
backups on just the randy image independent of other things on &lt;code&gt;nancy&lt;&#x2F;code&gt;’s side. So some kind of
&lt;code&gt;rsync&lt;&#x2F;code&gt; handoff to network storage, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1746&quot;&gt;1746&lt;&#x2F;h2&gt;
&lt;p&gt;I think next step is a grafana&#x2F;prometheus&#x2F;loki stack, I’m tired of having to jump all over creation
to find logs.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>12-AUG-2024</title>
        <published>2024-08-12T00:00:00+00:00</published>
        <updated>2024-08-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/12-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/12-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/12-aug-2024/">&lt;h2 id=&quot;2033&quot;&gt;2033&lt;&#x2F;h2&gt;
&lt;p&gt;Got some more stuff working w&#x2F; barge, needed to add &lt;code&gt;recommendedProxySettings&lt;&#x2F;code&gt; to each of the
proxied items. I still need to setup outbound VPN for these as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>11-AUG-2024</title>
        <published>2024-08-11T00:00:00+00:00</published>
        <updated>2024-08-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/11-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/11-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/11-aug-2024/">&lt;h2 id=&quot;1512&quot;&gt;1512&lt;&#x2F;h2&gt;
&lt;p&gt;Working on the hostkey problem, I’m starting simple, just getting it set for the non-persistent
(i.e., netbooted) machines, I also include a ‘generic’ one that I can use in case I don’t want to
generate one right away (more for testing new netbooted machines).&lt;&#x2F;p&gt;
&lt;p&gt;I’m planning to try for a “Nix Store over NFS” approach since my netbooted machines should be more
or less RO. I think that should make ‘most’ of the infrastructure non-persistent; though I haven’t
worked out exactly how I’m going to do the complicated dance there.&lt;&#x2F;p&gt;
&lt;p&gt;One upside of putting all my hostkeys in a single bucket is I &lt;em&gt;should&lt;&#x2F;em&gt; be able to pregenerate a
‘known-hosts’ file which I can actually trust to some extent, so that if I get an ‘unknown host’ it
would actually indicate something has gone awry.&lt;&#x2F;p&gt;
&lt;p&gt;At time of writing I’m just finishing up the experiment with &lt;code&gt;pinky&lt;&#x2F;code&gt; and will roll out the change
once it’s ready. I’ve kept all the keys in &lt;code&gt;narya&lt;&#x2F;code&gt;, so they’re out of the way for the moment.
Eventually these’ll move to Vault and be pulled in via &lt;code&gt;turnkey&lt;&#x2F;code&gt;, so they won’t need to be in any
repo.&lt;&#x2F;p&gt;
&lt;p&gt;This is also nice because it makes rotation pretty pleasant; I can just generate a new key, update
the relevant machines, and (eventually) regen my knownhost file appropriately.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2313&quot;&gt;2313&lt;&#x2F;h2&gt;
&lt;p&gt;Got storage pools set up, I think I need to write something to sync the xmls back and forth, since
the easiest way to manage these right now is just to copy the xml back and forth and do the
adjusting in virt-manager.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>10-AUG-2024</title>
        <published>2024-08-10T00:00:00+00:00</published>
        <updated>2024-08-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/10-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/10-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/10-aug-2024/">&lt;h2 id=&quot;1419&quot;&gt;1419&lt;&#x2F;h2&gt;
&lt;p&gt;Working on the DNS issue with toto, I’ve set it up so all of KANSAS is bypassing my internal DNS so
that normal operations are maintained, and only my laptop has DNS issues, while my main machine
(Hedges) is not so-encumbered, that way I’m able to work freely on &lt;code&gt;toto&lt;&#x2F;code&gt; without knocking everyone
offline, maintaining the most important invariant my lab must maintain:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Do not interrupt the Bluey.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I think the issue is probably with the new NSD stuff, I can still resolve some &lt;code&gt;.canon&lt;&#x2F;code&gt; addresses
but I suspect that’s just cache.&lt;&#x2F;p&gt;
&lt;p&gt;It’s always DNS that gets you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2251&quot;&gt;2251&lt;&#x2F;h2&gt;
&lt;p&gt;This turned out to be a simple bit of misconfiguration, using &lt;code&gt;.canon&lt;&#x2F;code&gt; instead of &lt;code&gt;.emerald.city&lt;&#x2F;code&gt;,
and a missing port open.&lt;&#x2F;p&gt;
&lt;p&gt;I like it when it’s simple.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>7-AUG-2024</title>
        <published>2024-08-07T00:00:00+00:00</published>
        <updated>2024-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/7-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/7-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/7-aug-2024/">&lt;p&gt;(and a bit of 6-AUG too)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0141&quot;&gt;0141&lt;&#x2F;h2&gt;
&lt;p&gt;I’m doing something wrong with the filesystem definitions, I need to rebuild the pool again.&lt;&#x2F;p&gt;
&lt;p&gt;I got the script using wwns to make sure it persists, but that wasn’t why the thing was breaking on
boot, to be honest, I’m not sure why it’s breaking on boot, but I think I might be able to skirt all
of this because of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nixos.wiki&#x2F;wiki&#x2F;ZFS#Mounting_pools_at_boot&quot;&gt;this&lt;&#x2F;a&gt;, but that needs a
rebuild.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1142&quot;&gt;1142&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got it mostly working with the automount, but I’d still like to understand what I was doing
wrong w&#x2F; the filesystem definitions; probably I needed to set different options or something, the
emergency shell never managed to start, so it’s hard to figure out exactly what went wrong.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I like the way I laid out the disks and want to extend the idea of the cadaster in that
way, building a large nixos-style module system that describes all my hardware (and maybe integrates
with the nascent &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;numtide&#x2F;nixos-facter&quot;&gt;nixos facter&lt;&#x2F;a&gt; tool) and then can be used
to populate other parts of the configuration by reference seems pretty handy.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately I think it also points at a way out of the nix ecosystem while still maintaining the
‘single common configuration system’ that I like about NixOS. There’s no reason to couple it to Nix
besides the convenience of the package manager, a declarative description of one’s hardware and
virtual hardware architecture is useful in it’s own right and could ostensibly be compiled to
instructions to configure virtually anything from a known starting state. My interest in it is
actually simpler, to boot, I just want to be able to simulate arbitrary architectures and employ
some kind of static analysis to surface issues at ‘compile time’; I think getting anywhere near that
for architecture design could be extremely valuable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1532&quot;&gt;1532&lt;&#x2F;h2&gt;
&lt;p&gt;I’m going to do some tweaking to the &lt;code&gt;cadaster&lt;&#x2F;code&gt; idea, I’m going to split it between &lt;code&gt;narya&lt;&#x2F;code&gt; and
&lt;code&gt;telperion&lt;&#x2F;code&gt;, two items with the same underlying schema, both provided as flake outputs, &lt;code&gt;telperion&lt;&#x2F;code&gt;
will pull in and merge &lt;code&gt;narya&lt;&#x2F;code&gt;’s definitions into it’s own at build time, but will otherwise be
unaware, that structure will then be available to all subsequent definitions. I’ll probably just
keep the hardware defs in &lt;code&gt;telperion&lt;&#x2F;code&gt; for now, but they may be extracted to &lt;code&gt;laurelin&lt;&#x2F;code&gt; later if that
seems prudent.&lt;&#x2F;p&gt;
&lt;p&gt;The structure will be something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    compute&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hostname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;        # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    storage&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        disks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;diskname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # includes a reference to `cadaster.compute.hostname` for where it&amp;#39;s installed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    network&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        switches&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;switchname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # Should include port maps and the like.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        routers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;routername&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        firewalls&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;firewallname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    racks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    power&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The idea is to represent each physical item in this with all it’s metadata, but none of it’s
configuration. Configuration then consumes this to build the actual configuration, and the
resulting configuration is then used to build the actual system images.&lt;&#x2F;p&gt;
&lt;p&gt;Essentially it’s DCIM-as-code. I’m sure this has been done before, but reinventing wheels is fun.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to build each chunk as nixos modules, and then I can use that to attach additional
computed information to each section. Ideally I can use this to drive some sort of
testing&#x2F;monitoring tools as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>5-AUG-2024</title>
        <published>2024-08-05T00:00:00+00:00</published>
        <updated>2024-08-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/5-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/5-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/5-aug-2024/">&lt;h2 id=&quot;1144&quot;&gt;1144&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got the format-disks stuff wrapped up in some Nix code now, I need to extend this into a
module, but essentially it just writes the &lt;code&gt;format-disks&lt;&#x2F;code&gt; script based on the Attrset I feed it; it
should be extensible to other machines, but does expect to be able to wipe all specified disks so
it’s still an imperative management strategy, I doubt there is a good declarative one for disks
since they are essentially entirely made of statefulness.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I plan to manage these disks imperatively and track changes via the CHANGELOG in the
cadaster, so it’s not a big issue.&lt;&#x2F;p&gt;
&lt;p&gt;Remaining on the TODO for this is:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Backups to Nancy (and thus to cloud)&lt;&#x2F;li&gt;
&lt;li&gt;Porting all the VMs over to use the disk I’ve set up&lt;&#x2F;li&gt;
&lt;li&gt;Setting up the NFS store on BTG&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;2331&quot;&gt;2331&lt;&#x2F;h2&gt;
&lt;p&gt;I started moving the ZFS configuration into a dedicated module. This is pretty unnecessary but I
wanted to start it and leave a branch to come back to later. I set up the existing configuration
with a simple ‘mode’ flage to control whether it leaves the ‘prepare’ script in place, or if it just
tries to mount the datasets. I’m not automatically calculating the filesystems, but I think that
will be easier to do when it’s properly a module and not just the shim.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>3-AUG-2024</title>
        <published>2024-08-03T00:00:00+00:00</published>
        <updated>2024-08-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/3-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/3-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/3-aug-2024/">&lt;h2 id=&quot;0026&quot;&gt;0026&lt;&#x2F;h2&gt;
&lt;p&gt;Had to revert &lt;code&gt;toto&lt;&#x2F;code&gt;, I think I remember having an issue where it would serve DNS without issue for
a while, then start refusing connections thereafter. I remember going to &lt;code&gt;unstable&lt;&#x2F;code&gt; helped with
that, but I don’t remember the details enough. I think there is a way to simply make NSD do the pass
through, but I need to go do some reading to remember how.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2036&quot;&gt;2036&lt;&#x2F;h2&gt;
&lt;p&gt;I have run into an issue with my netboot setup, which points to a more general issue I had been
punting off until now.&lt;&#x2F;p&gt;
&lt;p&gt;I have a bunch of machines I’d like to netboot that, ultimately, really shouldn’t be netbooted.
“Standard” (non-EFI) netbooting has a hard limit at a 4GB Ramdisk, and tbh, I don’t want to go
beyond that generally since things get quite memory hungry quickly, so while moving to an .efi-based
boot system is probably ‘good’ in the long term, it helps entrench a bit of bad design I admitted
while building things.&lt;&#x2F;p&gt;
&lt;p&gt;Now I’m caught out a little earlier than I wanted.&lt;&#x2F;p&gt;
&lt;p&gt;Initially I had planned to build &lt;code&gt;gehenna&lt;&#x2F;code&gt;, a machine that would be a nix-store-over-NFS server, but
I read that this was nontrivial and projects like &lt;code&gt;tvix&lt;&#x2F;code&gt; exist but aren’t yet ready for production.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally the system would work thus:&lt;&#x2F;p&gt;
&lt;p&gt;Boot every machine to a common nix image that is stripped to the barest essentials, and contains
only one post-boot script that asks it to be configured by some remote configurator. This base image
would mount a nix store over NFS specific to that machine, so that it can then be treated exactly as
if it were a ‘regular’ machine with a persistent nix store, but where that store is actually located
on the far side of a network connection. This has an obvious duplication issue (different machines
will likely share the same nix store objects, so they will be duplicated across the network), but I
figured:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Probably whatever native dedup happens would be sufficient to minimize the pain&lt;&#x2F;li&gt;
&lt;li&gt;I don’t really have a big enough architecture in mind to warrant fixing that storage problem
until I have it.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Then I read &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;xyno.space&#x2F;post&#x2F;nix-store-nfs&quot;&gt;this&lt;&#x2F;a&gt; which made me think I could do something
about halfway between what the author does and my idea. A main .ro store with a .rw store per
machine mounted over it, I didn’t actually realize this was possible with NFS, but it actually seems
pretty straightforward. The author there uses a tmpfs, but there is no reason I couldn’t use a
persistent store if I preferred, then I could factor out common values periodically into the .ro
side to minimize duplication.&lt;&#x2F;p&gt;
&lt;p&gt;I think this is a good idea, but I think it’s going to take a pile of work to get right, so I’m
going to focus for now on getting BTG formatted with ‘real’ storage so I can carve off a chunk for
my dev VM and do things ‘the old fashioned way’ with a real backing disk, but I definitely need to
do some more research on how to approach building &lt;code&gt;gehenna&lt;&#x2F;code&gt; and the NFS store.&lt;&#x2F;p&gt;
&lt;p&gt;I really like the idea of a sort of ‘stem cell’ VM that I can differentiate simply by mounting the
right underlying store and doing some command at it to ‘activate’ whatever configuration lives on
the other side of that, I don’t think such a thing would be too difficult. I could also see having a
simple .ro-only approach and having builds happen entirely on the &lt;code&gt;gehenna&lt;&#x2F;code&gt; side rather than the
client side, design is needed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2102&quot;&gt;2102&lt;&#x2F;h2&gt;
&lt;p&gt;A brief thought on the UEFI netbooting, in particular, this solves a major defect in terms of
security, BIOS netbooting (what I’m doing now) is only over insecure protocols, fine for a closed
lab, bad for anything that might ever be exposed to the internet, UEFI netbooting can be done over
HTTPS, so definitely needs doing, for now I have BTG and DOP both standing up on a netbooted image
via BIOS netbooting, so hopefully that unblocks me and I can return to UEFI later.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2-AUG-2024</title>
        <published>2024-08-02T00:00:00+00:00</published>
        <updated>2024-08-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/2-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/2-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/2-aug-2024/">&lt;h2 id=&quot;2335&quot;&gt;2335&lt;&#x2F;h2&gt;
&lt;p&gt;I’m working on committing off a bunch of work, I solved the DNS issue without adding a second phase,
it ultimately boiled down to needing to split and calculate each zone via the &lt;code&gt;nixosConfigTree&lt;&#x2F;code&gt;
instead of using the &lt;code&gt;nixosConfigurations&lt;&#x2F;code&gt; directly.&lt;&#x2F;p&gt;
&lt;p&gt;I have an annoying reversal that happens when calculating the &lt;code&gt;nixosConfigurations&lt;&#x2F;code&gt; that results in
the domain coming first – I haven’t fixed that yet but it’s so ugly I feel obligated to mention it
in the log.&lt;&#x2F;p&gt;
&lt;p&gt;I refactored some of the &lt;code&gt;deploy&lt;&#x2F;code&gt; scripts but &lt;code&gt;just&lt;&#x2F;code&gt; is really not up to what I’m putting it
through, I think. In particular the &lt;code&gt;nix flake update&lt;&#x2F;code&gt; logic is a bit of a mess and often runs a
couple times. This isn’t a huge issue, but it burns time; I suppose moving development to a VM will
help with that, but that would require I actually get that built, which isn’t as interesting as
chasing infinite recursion bugs.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I’m getting &lt;code&gt;toto&lt;&#x2F;code&gt; updated tonight, which unblocks &lt;code&gt;barge&lt;&#x2F;code&gt; and puts me back to where I
was with &lt;code&gt;ereshkigal&lt;&#x2F;code&gt; before cutting over. This whole process took about a month, but I think it was
a good move, except that I truly hate dealing with multiple git repos like this. I’ve looked at
using &lt;code&gt;worktrees&lt;&#x2F;code&gt; and they aren’t &lt;em&gt;quite&lt;&#x2F;em&gt; what I want.&lt;&#x2F;p&gt;
&lt;p&gt;Really what I want is a monorepo that isn’t a monorepo. I want each project to have an independent
history, but I also want to be able to tie commits together across repos. Right now when I make an
update in &lt;code&gt;telperion&lt;&#x2F;code&gt;, nothing coordinates it with &lt;code&gt;laurelin&lt;&#x2F;code&gt;. I &lt;em&gt;can&lt;&#x2F;em&gt; do this through flakes (make
each flake track via the remote git repo, update to specific SHAs, then do everything the ‘intended’
way, as I understand it), but this, plainly, sucks. Iteration on a change becomes difficult when
building it, and while it is very handy to create ‘canonical’ deployments of a suite of tools, it
isn’t great for hacking on a lab, where purity isn’t as valuable. I still want to be able to track
that compatibility information, but most of the time I want to do it outside of my actual IaC; and
instead have my ‘monorepo’ actually just be a bunch of independent git trees in the same git
&lt;em&gt;database&lt;&#x2F;em&gt;, but with an additional way to tie two commits together when they are ‘compatible’.
Ideally also allowing that tie to be revoked if a later discovery shows they aren’t compatible.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is still a little nascent, but I think this is doable in the context of &lt;code&gt;git&lt;&#x2F;code&gt; but with
different semantics to the standard &lt;code&gt;git&lt;&#x2F;code&gt; repo.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, I need another project like I need to increase my topological genus, so I’m just going
to focus on standing up some services and getting &lt;code&gt;btg&lt;&#x2F;code&gt; sorted.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1-AUG-2024</title>
        <published>2024-08-01T00:00:00+00:00</published>
        <updated>2024-08-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/1-aug-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/1-aug-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/1-aug-2024/">&lt;h2 id=&quot;0112&quot;&gt;0112&lt;&#x2F;h2&gt;
&lt;p&gt;Ran into an infinite recursion with my DNS generation, by referencing it directly, it has to query
it’s own configuration to calculate it’s DNS. I think this only happens for the &lt;code&gt;canon&lt;&#x2F;code&gt; domain
because of how I have split up the options. Since the &lt;code&gt;canon&lt;&#x2F;code&gt; domain is calculated from the configs,
and the config of the dns server wants to include the &lt;code&gt;canon&lt;&#x2F;code&gt; domain, it has to calculate it’s own
config and down the rabbit hole went Alice.&lt;&#x2F;p&gt;
&lt;p&gt;I think this is straightforward to fix, but I lack the will tonight. I can rely on precomputed files
and make this a compilation step that just runs when I run a deploy. It’s relatively quick to
calculate statically, then I can refer to the static copy. That also make it easy to inspect when
there are issues, and solves the ‘serial number in the git repo’ problem I haven’t yet mentioned
(the idea of trying to remember to maintain that number will result in many many many tiny commits
full of more swear words than delta).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>29-JUL-2024</title>
        <published>2024-07-29T00:00:00+00:00</published>
        <updated>2024-07-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/29-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/29-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/29-jul-2024/">&lt;h2 id=&quot;1748&quot;&gt;1748&lt;&#x2F;h2&gt;
&lt;p&gt;Over the weekend, I mostly refactored and tweaked things, and got DOP + it’s VMs up and netbooting.&lt;&#x2F;p&gt;
&lt;p&gt;I ran into an issue where building a bridge over a VLAN-split bond connection didn’t seem to work. I
spent almost no time debugging in it favor of getting the lab back to a working state; and just
pulled an interface to dedicate to it. I suspect this is mostly a switching problem (enabling trunk
ports or w&#x2F;e), but I want to converge both the WiFi and LAN networks eventually and split everything
via VLAN instead, so there’s no point in spending time on it now when I’m just going to radically
change it later.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;barge&lt;&#x2F;code&gt; and &lt;code&gt;pinky&lt;&#x2F;code&gt; are both building but need a bit of work on their networking setup, eventually
I’ll pull that config into laurelin as a module; I’m thinking about how I want to organize the
domains and get more of the libvirt config ported back into nix; but the idea is hazy right now, I
think ideally the individual networks per domain will have some &lt;code&gt;nix&lt;&#x2F;code&gt; representation that I can pass
in, so the function’d be something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;laurelin&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    networks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; link&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;domains&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo.bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;networks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo-net&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; ip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1.2.3.4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; link&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;domains&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo.bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;networks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo-net2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; ip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1.2.3.5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; link&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;domains&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo.bar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;networks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;foo-net3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; ip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1.2.3.6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This would then use the content of the &lt;code&gt;foo-net&lt;&#x2F;code&gt; attrset to populate all the networking config. It
&lt;em&gt;should&lt;&#x2F;em&gt; be possible to re-use this model for ‘real’ networks, but I’ll probably limit it to virtual
networks to start. Ideally I can work out my abovementioned issue in virtuo and then port back.&lt;&#x2F;p&gt;
&lt;p&gt;I can do a similar thing for the &lt;code&gt;domain&lt;&#x2F;code&gt; side of things, have a few ‘standard’ domains, then set a
key in &lt;code&gt;laurelin&lt;&#x2F;code&gt; just for data’s sake, to be used when deploying the config to a particular
host.&lt;&#x2F;p&gt;
&lt;p&gt;Unrelated to that, I started working on setting up &lt;code&gt;neotest&lt;&#x2F;code&gt; and want to start trying to get more of
the workflow into &lt;code&gt;vim&lt;&#x2F;code&gt; so I need to jump between fewer windows. &lt;code&gt;tmux&lt;&#x2F;code&gt; makes it hurt less, but I
want to have the lab integrated into the editor so I can more fluently manage, e.g., rebuilds and so
on. I think that comes on the back of setting up a laminar server and moving some of the
build&#x2F;deploy stuff there. That also means moving towards purity&#x2F;no more &lt;code&gt;--impure&lt;&#x2F;code&gt; builds, which is
it’s own can of worms.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I need to get some way to provide DNS includes, maybe creating a more abstract ‘reverse
proxy’ module that both configures an nginx service but also generates a zone-file w&#x2F; appropriate
CNAMEs would work here? Something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;laurelin&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    services&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        reverse-proxy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;parent.domain&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;subdomain&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                    frontendPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 80&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                    backendPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 8080&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;            }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I would have that generate both an nginxconfig and a key that could then be pulled by the
&lt;code&gt;show-dns&lt;&#x2F;code&gt; function in the flake? Ideally this would allow the ‘parent’ to exist as &lt;code&gt;hostname.canon&lt;&#x2F;code&gt;,
then have it populate &lt;code&gt;hostname.parent.domain&lt;&#x2F;code&gt; as a CNAME to &lt;code&gt;hostname.canon&lt;&#x2F;code&gt; and then have the
others similarly populate based on the desired subdomain.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1850&quot;&gt;1850&lt;&#x2F;h2&gt;
&lt;p&gt;I may be getting slightly ahead of myself w&#x2F; barge, I think I need to write a more general ‘docker
container’ module that I then feed additional items into, perhaps?&lt;&#x2F;p&gt;
&lt;p&gt;I also need a dev machine that isn’t this poor old laptop.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>27-JUL-2024</title>
        <published>2024-07-27T00:00:00+00:00</published>
        <updated>2024-07-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/27-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/27-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/27-jul-2024/">&lt;h2 id=&quot;0026&quot;&gt;0026&lt;&#x2F;h2&gt;
&lt;p&gt;Big pile of stuff done today, I did a ton of refactoring and cleaning, and I did a bit of secret
scrubbing as well. I also ported over all the modules from glamdring, so it should be ready to turn
public on github after a last once-over.&lt;&#x2F;p&gt;
&lt;p&gt;laurelin and telperion are also almost there, which is moderately terrifying, I get anxious about
these things.&lt;&#x2F;p&gt;
&lt;p&gt;Rather than process those emotions, I instead work on getting the domain xmls at least temporarily
loaded with some hacky work in the flake. I also have another hack from the refactoring to pull
common configuration out of the &lt;code&gt;cadaster&lt;&#x2F;code&gt;, a module in &lt;code&gt;telperion&lt;&#x2F;code&gt; where it does not belong. I plan
to move it over to laurelin after I’m done auditing the existing cadaster and pulling all the common
config out. Ideally &lt;code&gt;cadaster&lt;&#x2F;code&gt; is really only the hardware configuration and stuff related to
building the base image. In the end all my machines will be a collection of &lt;code&gt;laurelin&lt;&#x2F;code&gt;, &lt;code&gt;glamdring&lt;&#x2F;code&gt;,
and &lt;code&gt;narya&lt;&#x2F;code&gt; configuration, everything else gets split up.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0042&quot;&gt;0042&lt;&#x2F;h2&gt;
&lt;p&gt;Fixed an issue where unfree packages weren’t allowed and that meant 1pass couldn’t build. However,
that got me thinking that it’d be better to export &lt;code&gt;NIXPKGS_ALLOW_UNFREE&lt;&#x2F;code&gt;, since there is no reason
to litter the codebase with unfree tags when I can just export a variable in the devshell once that
I can turn off if I want to see if I’m using anything unfree.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1227&quot;&gt;1227&lt;&#x2F;h2&gt;
&lt;p&gt;I just made public all the component repos except &lt;code&gt;elenta&lt;&#x2F;code&gt; and &lt;code&gt;narya&lt;&#x2F;code&gt;, the former because there is
nothing there (and TBH I may collapse it away into &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; proper), and the latter for
obvious reasons.&lt;&#x2F;p&gt;
&lt;p&gt;I started thinking about making &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; a bit more of a general monorepo for my projects,
which would point to moving a lot of my existing automation out to &lt;code&gt;elenta&lt;&#x2F;code&gt; and having just
project-management stuff in this repo, but I haven’t really decided on organization yet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>25-JUL-2024</title>
        <published>2024-07-25T00:00:00+00:00</published>
        <updated>2024-07-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/25-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/25-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/25-jul-2024/">&lt;h2 id=&quot;2341&quot;&gt;2341&lt;&#x2F;h2&gt;
&lt;p&gt;Got dragon-of-perdition fixed up and booting. I also got all his interfaces bonded and running as
one unit. I need to read about the other options, but they all look pretty straightforward.&lt;&#x2F;p&gt;
&lt;p&gt;I also refactored the Justfile a bunch, and got netboot image creation moved into a flake ‘app’.
It mostly works, but is quite messy, so I’m going to think about some ways to clean it up.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>24-JUL-2024</title>
        <published>2024-07-24T00:00:00+00:00</published>
        <updated>2024-07-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/24-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/24-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/24-jul-2024/">&lt;h2 id=&quot;1445&quot;&gt;1445&lt;&#x2F;h2&gt;
&lt;p&gt;I set up canon IPs for both of the DRACs on the two R730s (DOP and BTG), but for whatever reason I
can’t get to them via the DNS address, only by their IP, not a big deal for now, but annoying.&lt;&#x2F;p&gt;
&lt;p&gt;Archimedes is hooked back up to the barrier server, cleaned up some stuff in the &lt;code&gt;Justfile&lt;&#x2F;code&gt; and
started in on the netboot image. I need to figure out what to include in the imports path (if
anything), and then go from there.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2248&quot;&gt;2248&lt;&#x2F;h2&gt;
&lt;p&gt;I think I want to rewrite a bunch of the image-building stuff.&lt;&#x2F;p&gt;
&lt;p&gt;The script I have is very clunky, and I think I could pretty easily adapt the existing script in nix
to just work with my setup directly, but I’d have to introduce a couple new ideas.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, There is a sort of ‘hyperparameter’ that I need to introduce, something that is
specific to my setup, namely – where I store the netboot images – but which is not really a detail
that fits in any of the existing flakes in the blizzard, so to speak.&lt;&#x2F;p&gt;
&lt;p&gt;I suppose &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; is the natural place for such things, but I could also make an argument
that much of what I plan to do in &lt;code&gt;elenta&lt;&#x2F;code&gt; is similar.&lt;&#x2F;p&gt;
&lt;p&gt;I think, however, my idea has evolved somewhat. Where &lt;code&gt;elenta&lt;&#x2F;code&gt; was originally going to be the
&lt;code&gt;flying-monkey&lt;&#x2F;code&gt; replacement, and sort of the operational arm of the thing (with &lt;code&gt;laurelin&lt;&#x2F;code&gt; being the
abstract library from which &lt;code&gt;telperion&lt;&#x2F;code&gt; both describes the physical architecture (the ‘cadaster’,
and also describes abstract configurations of that architecture (‘domains’). I also had intended for
&lt;code&gt;elenta&lt;&#x2F;code&gt; to manage mapping those &lt;code&gt;domains&lt;&#x2F;code&gt; onto the physical architecture.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’m going to purpose &lt;code&gt;elenta&lt;&#x2F;code&gt; solely towards that goal, and pull all the operational stuff
into &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt;, additionally, it can contain the ‘hyperconfiguration’ which can be passed into
scripts and so on (but ideally isn’t referred to in and of the other flakes). The first such element
of the hyperconfiguration is the &lt;code&gt;minas-tarwon.netboot_store&lt;&#x2F;code&gt;, which is some structured
configuration that referents will use to know where netboot images are stored, e.g.:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;minas-tarwon&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;netboot_store&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;path&#x2F;to&#x2F;store&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’ll try to encode as much of my scripting to nix, so it can natively refer to things, then wrap
these outputs with a just script.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>23-JUL-2024</title>
        <published>2024-07-23T00:00:00+00:00</published>
        <updated>2024-07-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/23-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/23-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/23-jul-2024/">&lt;h2 id=&quot;0014&quot;&gt;0014&lt;&#x2F;h2&gt;
&lt;p&gt;Got deploys tested, and am now serving the &lt;code&gt;.canon&lt;&#x2F;code&gt; domain on &lt;code&gt;toto&lt;&#x2F;code&gt;. I realized I need to get
&lt;code&gt;ifrit&lt;&#x2F;code&gt; added to the cadaster, and it presents a wrinkle, as it is on multiple networks, and thus
would need multiple canon IPs, since bonding these is not really reasonable since they &lt;em&gt;need&lt;&#x2F;em&gt; to
serve actually indepentent networks in my architecture. My topology splits lab and non-lab networks,
and I want my firewall to maintain that separation, while having, ideally, a single flat network
that stretches across both. Moving the point of failure to my firewall, instead of the lab switch.&lt;&#x2F;p&gt;
&lt;p&gt;This is the theory, and it means that &lt;code&gt;ifrit&lt;&#x2F;code&gt; will need at least two entries. I think that’s okay,
and ultimately it makes convenient the fact that I’m stealing a whole TLD for this. I can just use
subdomains.&lt;&#x2F;p&gt;
&lt;p&gt;!!! CAUTION&lt;&#x2F;p&gt;
&lt;p&gt;This, by the way, is not a good way to use DNS, there are a variety of ways to exploit this kind of
thing if you aren’t careful, but this lab is confined to me, for the most part, and ultimately I’m
not super worried as I do plan to make sure requests for these domains never leave the network. This
can itself be bad because if the domains are ‘real’ (i.e., if you’re split-horizoning a real
domain), then you can block an otherwise ‘correct’ lookup. Generally you’ll be fine if you use weird
TLDs and block all outgoing DNS for those TLDs (which is what I do). You can be much safer by just
buying a domain and using that, but I like punned names and I don’t want to pay for a problem I’m
unlikely to ever actually have.&lt;&#x2F;p&gt;
&lt;p&gt;Each independent network on ifrit can have it’s own subdomain to point to the gateway. This means
that when I start serving multiple domains and layering VLANs, I can have as many subdomains as I
like.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, next step is to get &lt;code&gt;ifrit&lt;&#x2F;code&gt; into the cadaster and update the DNS stuff to allow for
multiple subdomains for ifrit. Then I can update &lt;code&gt;ifrit&lt;&#x2F;code&gt; to point it’s clients at the DNS IP and I
think I’m basically back up and running in the new setup.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1220&quot;&gt;1220&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at a new issue, &lt;code&gt;toto&lt;&#x2F;code&gt; has two IPs on the same interface, one is virtual, and &lt;code&gt;iptables&lt;&#x2F;code&gt; nor
&lt;code&gt;nftables&lt;&#x2F;code&gt;-based local firewalls seem to be able to handle this case with the built-in networking
module. I’m not sure I understand exactly how things are getting generated just yet, but my guess is
that this is not a typical way to cut up a network and so the implementation is not robust to my
particular breed of weirdo.&lt;&#x2F;p&gt;
&lt;p&gt;If I turn off the firewall, everything works, and so I know the issue is local to the machine. I
tried just inspecting both the configurations generated by my config and they both look ‘fine’ in
the sense that they should happily be sending packets to the specified interface, so after some
consternation, I turned my attention further up the stack.&lt;&#x2F;p&gt;
&lt;p&gt;The tipoff to this was looking at the &lt;code&gt;dmesg&lt;&#x2F;code&gt; output as I tried to hit port 53 w&#x2F; an nmap scan; it
shows that when I run the &lt;code&gt;nmap&lt;&#x2F;code&gt; against that port, it sees the incoming connection as originating
from the &lt;code&gt;enp2s0&lt;&#x2F;code&gt; interface, and not the &lt;code&gt;enp2s0_dns&lt;&#x2F;code&gt; virtual interface. &lt;code&gt;enp2s0&lt;&#x2F;code&gt; does not have &lt;code&gt;53&lt;&#x2F;code&gt;
open.&lt;&#x2F;p&gt;
&lt;p&gt;I tried opening &lt;code&gt;53&lt;&#x2F;code&gt; on &lt;code&gt;enp2s0&lt;&#x2F;code&gt; itself and sure enough everything works fine. So for now I suppose
I’ll just have to open the sum of all the ports I want on the &lt;code&gt;enp2s0&lt;&#x2F;code&gt; interface and then later do
something bespoke to handle my weird networking idea.&lt;&#x2F;p&gt;
&lt;p&gt;I’m now seeing what I suspect is a very straightforward “need to turn some ports on” issue on the
switch, so that’s tonight’s project.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1738&quot;&gt;1738&lt;&#x2F;h2&gt;
&lt;p&gt;Truly confusing, even with the extra port, it actually just shows the port as open, doesn’t actually
respond correctly. For now I’ve just disabled the firewall entirely, I’m sure I’m doing something
silly, I just can’t track down what at the moment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2205&quot;&gt;2205&lt;&#x2F;h2&gt;
&lt;p&gt;Got the DNS configured for both KANSAS and CONDORCET. I should probably add the wifi router and
cable modem to the cadaster (and really everything in the racks, I suppose it should try to cover
everything that touches my network, at least).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2212&quot;&gt;2212&lt;&#x2F;h2&gt;
&lt;p&gt;I also updated NFS rules for nancy. This gets network storage back to functional.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>22-JUL-2024</title>
        <published>2024-07-22T00:00:00+00:00</published>
        <updated>2024-07-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/22-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/22-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/22-jul-2024/">&lt;h2 id=&quot;0916&quot;&gt;0916&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’ve got a better idea on how to organize things.&lt;&#x2F;p&gt;
&lt;p&gt;A deployment of a constellation is a derivation. It’s build phase creates and caches all the
cross-environment artifacts (zonefiles, images, etc), it’s install phase is a script that gathers
those artifacts and deploys them to the target machines and ensures all netboot images are up to
date.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;elenta&lt;&#x2F;code&gt; should provide these derivations given the constellation input, and then &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; can
take those derivations and apply them to the target machines.&lt;&#x2F;p&gt;
&lt;p&gt;Two different derivations are ‘compatible’ if they do not:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Overallocate any underlying machine&lt;&#x2F;li&gt;
&lt;li&gt;Have contradictory configurations (i.e., colliding ports, colliding filesystem
assignments&#x2F;mounts, etc).&lt;&#x2F;li&gt;
&lt;li&gt;Can be &lt;code&gt;mkMerge&lt;&#x2F;code&gt;d with each other and still have any assertions&#x2F;tests pass&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Ultimately this would allow breaking down that ‘main’ derivation into, e.g., a derivation per
machine or however else I want to break things up. It also makes the deployment pipeline
straightforward. “Here are a bunch of constellations that &lt;code&gt;elenta&lt;&#x2F;code&gt; compiles down to a single script
that you run from a provisioning machine to deploy everything specified.” Rollback is just applying
the previous derivation + whatever backup restoration should be done.&lt;&#x2F;p&gt;
&lt;p&gt;Automating a pre-deploy backup can be part of the &lt;code&gt;installPhase&lt;&#x2F;code&gt; of the derivation.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually it’d be cool to have the &lt;code&gt;merge&lt;&#x2F;code&gt; bit be smart and try to create, e.g., VMs and stuff
dynamically, so it just becomes a ‘map machine roles to resources, don’t care about where they are
hosted’&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1054&quot;&gt;1054&lt;&#x2F;h2&gt;
&lt;p&gt;I think I’m just going to leverage &lt;code&gt;just&lt;&#x2F;code&gt; in the &lt;code&gt;minas-tarwon&lt;&#x2F;code&gt; repo to port over the
&lt;code&gt;flying-monkey&lt;&#x2F;code&gt; stuff. It can do the basic deployment from &lt;code&gt;telperion&lt;&#x2F;code&gt; -&amp;gt; machine config for now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2317&quot;&gt;2317&lt;&#x2F;h2&gt;
&lt;p&gt;I set up &lt;code&gt;just&lt;&#x2F;code&gt; to do deploys now, porting over &lt;code&gt;flying-monkey&lt;&#x2F;code&gt; was pretty easy, I rather like
&lt;code&gt;just&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next I need to get the &lt;code&gt;canon&lt;&#x2F;code&gt; domain hosted. I just need to see how to refer to my own flake, I am
pretty sure I can just pass it down as a special arg. Not sure.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>21-JUL-2024</title>
        <published>2024-07-21T00:00:00+00:00</published>
        <updated>2024-07-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/21-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/21-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/21-jul-2024/">&lt;h2 id=&quot;1306&quot;&gt;1306&lt;&#x2F;h2&gt;
&lt;p&gt;I was thinking about the constellation file a little more last night, and I think I prefer this
design instead:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;rec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;machine.canon.lan&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        hostConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;null | { literal, module } | import .&#x2F;path&#x2F;to&#x2F;machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        vms&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;vm1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{ literal, module } | import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        containers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;container1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{ literal, module } | import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;        # arbitrary config available to be placed and used here.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;machine2.canon.wifi&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;        # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&quot;machine&quot;&lt;&#x2F;code&gt; key is the canon name of the machine, and there are options to configure items at
the host level, to spin up vms, or containers. &lt;code&gt;vms&lt;&#x2F;code&gt; and &lt;code&gt;containers&lt;&#x2F;code&gt; both take literal
configurations and spin up containers&#x2F;vms on the target. Additionally if these items are non-empty,
it will contribute appropriate configuration to the host to support them.&lt;&#x2F;p&gt;
&lt;p&gt;Canon addresses are also extended to include protocol type, this is something I’m toying with, I’d
prefer to have all interfaces bonded and then have a single logical address, but I’m not sure how
good of an idea it is to bond wireless and LAN interfaces, so I’m toying with separating them at
least at that level.&lt;&#x2F;p&gt;
&lt;p&gt;Unrelated, the issue I saw with &lt;code&gt;toto&lt;&#x2F;code&gt; seems to have resolved itself, so I’m guessing it was just
stale DHCP leases causing trouble.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1410&quot;&gt;1410&lt;&#x2F;h2&gt;
&lt;p&gt;One of the things I’m going to want to figure out is some mechanism to figure out when machines need
to be updated to match a specific SHA within the context of a specific constellation. Ultimately I
want a tool that can take a constellation and figure out how to rebuild everything to bring the
constellation into compliance with the config. Not sure how to do that yet, I’m sure there is some
git magic to be done, but I’m not sure what it is yet.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1645&quot;&gt;1645&lt;&#x2F;h2&gt;
&lt;p&gt;I’m a little stuck, trying to build up to the constellation&#x2F;role&#x2F;machine mapping system is going to
take a lot longer than I’d like, and I’m considering just manually managing the machines directly
for the short term and then extracting configurations out after the fact. This will inevitably leave
a big mess in the cadaster, but I think I can limit it by putting all the bespoke config in it’s own
file and relying on the laurelin modules directly there.&lt;&#x2F;p&gt;
&lt;p&gt;If I do that, then I can develop all the modules, get them tested and wired up, then the
constellation stuff won’t have the issue of needing to have both the modules and wireup system
debugged.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to go that route, and just add a &lt;code&gt;bespoke.nix&lt;&#x2F;code&gt; into which all the stuff that ‘should’ be a
machine role will go into, then later I can start to unpack that.&lt;&#x2F;p&gt;
&lt;p&gt;This also means that I can build everything around the .canon domain for now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2132&quot;&gt;2132&lt;&#x2F;h2&gt;
&lt;p&gt;Definitely liking the idea from earlier, I’m just placing it in the &lt;code&gt;config.nix&lt;&#x2F;code&gt; for now, but I
should be able to stand up everything pretty quickly this way, I can just use a &lt;code&gt;flying-monkey&lt;&#x2F;code&gt;
style script right now. I have a ton of pending changes to close in &lt;code&gt;telperion&lt;&#x2F;code&gt; and &lt;code&gt;laurelin&lt;&#x2F;code&gt; now,
so I’m going to work on that tonight and then probably take some time this week to start getting the
deployment pipeline working and &lt;code&gt;nfs&lt;&#x2F;code&gt; and &lt;code&gt;dns&lt;&#x2F;code&gt; working for the &lt;code&gt;canon&lt;&#x2F;code&gt; domain.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>20-JUL-2024</title>
        <published>2024-07-20T00:00:00+00:00</published>
        <updated>2024-07-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/minas-tarwon/20-jul-2024/"/>
        <id>https://disturbed-circles.com/log/minas-tarwon/20-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/minas-tarwon/20-jul-2024/">&lt;h2 id=&quot;2307&quot;&gt;2307&lt;&#x2F;h2&gt;
&lt;p&gt;Overall today I’ve got &lt;code&gt;toto&lt;&#x2F;code&gt;, &lt;code&gt;nancy&lt;&#x2F;code&gt;, and &lt;code&gt;archimedes&lt;&#x2F;code&gt; all on the &lt;code&gt;10.255.0.0&#x2F;16&lt;&#x2F;code&gt; network, mostly
manually configured. I need to build the deploy script in &lt;code&gt;elenta&lt;&#x2F;code&gt; and get the netboot image
generation and direct configuration application working.&lt;&#x2F;p&gt;
&lt;p&gt;I saw a recurrence of an old issue where ssh connections hang after some amount of time, I think it
relates to old DHCP leases, and I believe I’ve resolved it.&lt;&#x2F;p&gt;
&lt;p&gt;The other thing I am missing is some tooling to manage the switches. I’m hopeful I can repair the
old switch which died (prompting all this work happening so suddenly, I had planned a more gentle
transition), but I need a way to better manage the switch configuration, so I’d like to add tooling
in &lt;code&gt;elenta&lt;&#x2F;code&gt; to manage that as well.&lt;&#x2F;p&gt;
&lt;p&gt;In the short term I may just port &lt;code&gt;flying-monkey&lt;&#x2F;code&gt; and &lt;code&gt;build-img&lt;&#x2F;code&gt; from &lt;code&gt;ereshkigal&lt;&#x2F;code&gt; and serve them
out of &lt;code&gt;elenta&lt;&#x2F;code&gt;; &lt;code&gt;elenta&lt;&#x2F;code&gt; can pull in &lt;code&gt;narya&lt;&#x2F;code&gt; and &lt;code&gt;telperion&lt;&#x2F;code&gt; and provide a version of
&lt;code&gt;flying-monkey&lt;&#x2F;code&gt; to manually manage machines based on their &lt;code&gt;canon&lt;&#x2F;code&gt; address. I’d like to improve the
ergonomics to just need the &lt;code&gt;canon&lt;&#x2F;code&gt; name of the machine, then have it look up the IP at least
optionally without relying on DNS.&lt;&#x2F;p&gt;
&lt;p&gt;I can also have it introspect and get the &lt;code&gt;MAC&lt;&#x2F;code&gt; of the relevant machine for image building, the CLI
should be something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Build an image and place it at the specified location&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elenta build-image&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.#machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --out&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;path&#x2F;to&#x2F;store&#x2F;image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Build an image for the given MAC, store it under that MAC in the given &amp;#39;store&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elenta build-image&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.#machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --mac&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 00:11:22:33:44:55&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --store&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;path&#x2F;to&#x2F;netboot&#x2F;store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Build an image for the given machine by it&amp;#39;s canon, with the given role.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elenta build-image&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.#machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;machine.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --store&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;path&#x2F;to&#x2F;netboot&#x2F;store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Deploy a role to a machine by it&amp;#39;s canon name, do not boot to it on reboot (equiv to `nixos-rebuild test`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elenta deploy&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.#machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;machine.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Deploy a role to a machine and set it to boot to it on reboot (equiv to `nixos-rebuild switch`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elenta switch&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.#machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;machine.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Optionally use `--no-dns` to look up the mapping directly in telperion (useful for IP changes)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elenta deploy&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.#machine-role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;machine.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; --no-dns&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;elenta&lt;&#x2F;code&gt; is going to have a concept of &lt;code&gt;constellations&lt;&#x2F;code&gt;, which I suppose are similar to helm charts
or compose files, excepting that it’s a mapping of machine roles to machines, and expects that
configurations support whatever other systems you want to run.&lt;&#x2F;p&gt;
&lt;p&gt;The upshot of these is that you gain a separation between arbitrary physical hardware and the
logical design of your architecture. You can spend all your time designing an entirely abstract
architecture, and then distribute roles to machines independently.&lt;&#x2F;p&gt;
&lt;p&gt;The API I think looks a bit like&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Note this is a sketch, I don&amp;#39;t think you can import flake components like that.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;rec&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    roles&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        reverse-proxy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;flake:telperion#domains.example.tld.roles.reverse-proxy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        app-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;flake:telperion#domains.example.tld.roles.app-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        database&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;flake:telperion#domains.example.tld.roles.database&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;    mapping&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        domain&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;example.tld&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        redirect_bare_to&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;www&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        machines&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;www&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                role&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; roles&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;reverse-proxy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                host&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;server-a.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                extraOpts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                    # Arbitrary extra options to pass to the role&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;app&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                role&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; roles&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;app-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # Since these two are on the same machine, the mapping will try to merge the two&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;                # configurations, if they can&amp;#39;t be merged, it will fail with an error.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                host&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;server-a.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # Here we might assume that the roles have modes which tell it how to look for other db&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # instances, again, the goal of this is to try to only think about the allocation of&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;            # roles to hardware, and only pass information as is strictly necessary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;db-a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                role&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; roles&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;database&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                host&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;server-b.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                extraOpts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                    mode&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;db-b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                role&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; roles&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;database&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                host&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;server-c.canon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                extraOpts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;                    mode&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;secondary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-invalid z-illegal&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;elenta&lt;&#x2F;code&gt; will have access to the full mapping and can pass that down to the role configurations, so
roles can look up items in the constellation and use that for static service discovery; elenta can
also use this mapping to generate DNS configuration that creates a zonefile for the particular
domain that creates all the necessary records.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually it’d be cool to include switch configurations as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>4-JUL-2024</title>
        <published>2024-07-04T00:00:00+00:00</published>
        <updated>2024-07-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/4-jul-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/4-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/4-jul-2024/">&lt;h2 id=&quot;1713&quot;&gt;1713&lt;&#x2F;h2&gt;
&lt;p&gt;Been picking at this all day, managed to get Arena to connect to Hazel and for Hazel to dump it’s
logs somewhere other than STDOUT. I imagine I could have the thing continue to dump logs to STDOUT
but I’m not sure if that’ll cause weirdness later with the UI, so I’m just going to leave it sending
to &lt;code&gt;&#x2F;tmp&#x2F;hazel.log&lt;&#x2F;code&gt; until I have some UI in place.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’m going to work towards getting it making random moves and generally implementing the rest
of UCI for now. I also want to get it so that when &lt;code&gt;debug&lt;&#x2F;code&gt; is turned on, the &lt;code&gt;debug&lt;&#x2F;code&gt; log level is
set on the subscriber, and otherwise leave it at &lt;code&gt;info&lt;&#x2F;code&gt;. That way I can continue to use Arena as a
debugging mechanism.&lt;&#x2F;p&gt;
&lt;p&gt;I slapped together a couple scripts for running &lt;code&gt;cargo test&lt;&#x2F;code&gt; and &lt;code&gt;cargo build&lt;&#x2F;code&gt; with warnings
suppressed. I wish this was an option on the command itself instead of a flag. I recognize the ‘good
practice’ of always leaving these on, but I think it’s a little misguided, most of the time I
prioritize fixing the thing I’m working on, and because the error occasionally pop up in the middle
of all the warnings, it’s hard to track down the error amidst them.&lt;&#x2F;p&gt;
&lt;p&gt;I did a little experimenting with &lt;code&gt;watchman&lt;&#x2F;code&gt; and I think it may be worth a little hackery to come up
with something that will automatically, incrementally rerun tests and give you a little grid display&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;log output of failing tests. Mostly I want it to exist, I don’t know that I actually want to build
such a thing.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In any case, good progress today, hopefully I can get most of the protocol implemented and see if it
can help me debug any of the weird EP bugs I’ve been seeing.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>3-JUL-2024</title>
        <published>2024-07-03T00:00:00+00:00</published>
        <updated>2024-07-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/3-jul-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/3-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/3-jul-2024/">&lt;h2 id=&quot;0941&quot;&gt;0941&lt;&#x2F;h2&gt;
&lt;p&gt;I think the UI is in a good spot to leave for a minute while I bring in some of the components that
need the UI. The first round is a simple UCI REPL; I should be able to type raw UCI into the UI and
have it respond (probably with dummy info for now). It should expose an option “current engine” that
points to the relevant backend by name.&lt;&#x2F;p&gt;
&lt;p&gt;I also managed to re-introduce an en passant bug, I’m going to leave it for now; I started on a
refactored movegen module before I put the project down last time, I think that’s probably the
‘right’ way to chase out these bugs, and I think having a better debugging tool will help a lot in
figuring out what the issue is.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1145&quot;&gt;1145&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve roughed in the UCI repl a bit, just the parsing stuff. I’m going to get a basic
parse-to-an-enum, then refactor to use Hazel types for Moves&#x2F;etc. Those are generic enough that it
should help with forwarding UCI around but also being ergonomic enough to use directly in the UI and
for Hazel.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1320&quot;&gt;1320&lt;&#x2F;h2&gt;
&lt;p&gt;Fully roughed in, no type fanciness yes, but I’ll enrich the parsing as I need it. I think the next
step is to get the OCI connection started up, and then work on a backend which proxies the OCI
connection to the backend engine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1335&quot;&gt;1335&lt;&#x2F;h2&gt;
&lt;p&gt;I think I need to learn &lt;code&gt;tokio&lt;&#x2F;code&gt;. I keep hemming and hawing about just writing my own threadpool
thing, but I should probably learn the ‘real’ tool instead of rolling my own here. Time for more
tutorial reading, I guess.&lt;&#x2F;p&gt;
&lt;p&gt;Or not, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;corrode.dev&#x2F;blog&#x2F;async&#x2F;&quot;&gt;this article&lt;&#x2F;a&gt; suggests that maybe threads are just fine. I
don’t know that this needs to be such a giant thing, I’m comfortable having lots of otherwise idle
threads with connections open. I suppose maybe a better approach would be to have a
thread-per-engine, and then keep them in a pool. I suppose I could have &lt;code&gt;Grid&lt;&#x2F;code&gt; be abstract across
any &lt;code&gt;Engine&lt;&#x2F;code&gt;, and then have &lt;code&gt;Engine&lt;&#x2F;code&gt; be a trait which, e.g., &lt;code&gt;HazelEngine&lt;&#x2F;code&gt; might implement.&lt;&#x2F;p&gt;
&lt;p&gt;The trait would just expect a way to send it UCI messages and recieve them in return. Eventually I
can place another variant which supports, e.g., a protobuf-defined API or something. The API would
have a &lt;code&gt;raw_uci&lt;&#x2F;code&gt; message so you could always fall back to just parsing UCI, but for richer queries I
could extend it.&lt;&#x2F;p&gt;
&lt;p&gt;I think I’ll skip &lt;code&gt;tokio&lt;&#x2F;code&gt; for now and stick with threads until it starts hurting.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2143&quot;&gt;2143&lt;&#x2F;h2&gt;
&lt;p&gt;Definitely a pass on &lt;code&gt;tokio&lt;&#x2F;code&gt;, the docs say that I’m probably not the right case for it right now,
and if I can go with a threaded approach, go with a threaded approach, so that sounds like a good
reason to me.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to work on getting the ‘Driver’ part of Hazel working, that’s going to be the thing that
actually takes UCI messages and plays the game. My goal is going to be to integrate the UCI parser I
just wrote with the &lt;code&gt;Game&lt;&#x2F;code&gt; struct, and implement whichever commands feel easy and bail on the rest.
That should be enough for me to hook hazel up to an OTS GUI, and then I can get something relatively
bug free working on a known-good GUI before working to implement my own. I can also hopefully hook
up my UI and the OTS one at the same time, so I can compare when debugging.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1-JUL-2024</title>
        <published>2024-07-01T00:00:00+00:00</published>
        <updated>2024-07-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/1-jul-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/1-jul-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/1-jul-2024/">&lt;h2 id=&quot;2242&quot;&gt;2242&lt;&#x2F;h2&gt;
&lt;p&gt;Got the Ratatui UI roughed in; also sketched out a plan for the debugging
interface&#x2F;engine-tournament-manager thing. I’m off on a rabbit trail, but it seems fun so probably
worth doing.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing I want to do is get some sort of widget built to display a chessboard, I don’t think
that should be too difficult, since I’ve got half an implementation in the Debug impl for Ply.&lt;&#x2F;p&gt;
&lt;p&gt;I can’t say I know enough about &lt;code&gt;ratatui&lt;&#x2F;code&gt; so far to have an opinion, but I’ll say for sure that the
markup-in-Rust thing is not my favorite. Copilot actually helps a bit here, these APIs kind of suck
to remember; I frequently get simple transpotition errors where I miscapitalize or whatever. Copilot
eventually figures out what I’m trying to do and at least makes the mistakes for me, so I’m just
fixing what it fucks up instead of me making the mistake and feeling bad about it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2307&quot;&gt;2307&lt;&#x2F;h2&gt;
&lt;p&gt;Futzing more, I think it makes sense to include all the UI stuff in the library proper, and maybe
just gate it by a feature someday. I can implement widgets directly against the types in the
library, which seems nicer than having to wrap things in a newtype to widget them.&lt;&#x2F;p&gt;
&lt;p&gt;I’m definitely not quite doing it right w&#x2F; rendering, this is because I’m procrastinating reading
the rest of this tutorial.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>30-JUN-2024</title>
        <published>2024-06-30T00:00:00+00:00</published>
        <updated>2024-06-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/30-jun-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/30-jun-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/30-jun-2024/">&lt;h2 id=&quot;0102&quot;&gt;0102&lt;&#x2F;h2&gt;
&lt;p&gt;Been working on the EP_CAPTURE issue, I ended up just deleting the implementation, walking away for
a bit, then reimplementing. I ended up doing it a slightly different way than the inital bit
mangling trick I was trying, and I think I’m just going to leave it as is for now. I think the bit
mangling will be faster and I was probably just doing it wrong, but I can leave the optimization for
another day.&lt;&#x2F;p&gt;
&lt;p&gt;I added some better error output for the unrecoverable error branch, and managed to get the &lt;code&gt;perft&lt;&#x2F;code&gt;
test running (but getting a different count of positions than it should).&lt;&#x2F;p&gt;
&lt;p&gt;I need to set up some kind of integration test w&#x2F; a known-good engine. I think I might try switching
off the movegen for a bit and work on the UCI implementation and maybe a little TUI for debugging. I
could then ostensibly get it and stockfish talking to each other, and it could then start perfting
and having SF verify the results, so I can start to see the game state that led to it overcounting.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, for now, EP_CAPTURE I think is working, and I won’t really be able to track down the
bug until I build up some better tools for debugging.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1838&quot;&gt;1838&lt;&#x2F;h2&gt;
&lt;p&gt;A rough design:&lt;&#x2F;p&gt;
&lt;p&gt;Hazel: The main thread, spawns:
- Grid: A list of engine instances, defaulting to Hazel, but allowing arbitrary UCI connections
to other engines.
- UI: The UI thread
- Race Control: Which sends commands between engines &#x2F; the UI, may be part of the main Hazel thread
instead of it’s own thing, not really sure.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is to let Hazel have a sort of ‘tournament management’ feature, where it can run multiple
different engines and manage games between them, and also allow for deep integration tests as above.&lt;&#x2F;p&gt;
&lt;p&gt;The Engine Instance is a UCI Socket for communicating to the engine, which Hazel manages and the UI
allows selection between, messages are proxied down to the actual engine instance, which is just
running it’s own UCI client reading from the same socket.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>22-JUN-2024</title>
        <published>2024-06-22T00:00:00+00:00</published>
        <updated>2024-06-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/22-jun-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/22-jun-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/22-jun-2024/">&lt;h2 id=&quot;0143&quot;&gt;0143&lt;&#x2F;h2&gt;
&lt;p&gt;Worked a bit on EP_CAPTURE, but it appears that the &lt;code&gt;unmake&lt;&#x2F;code&gt; method marked &lt;code&gt;todo!()&lt;&#x2F;code&gt; that I started
implementing isn’t actully getting called in my test that explicitly exercises the unmake function
for this. It seems to be failing further up the chain, so I managed to stumble on a different bug
while trying to get perft working up to 6-ply.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1221&quot;&gt;1221&lt;&#x2F;h2&gt;
&lt;p&gt;I think the issue may be that it’s not properly recording that the previous move was an en passant?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1318&quot;&gt;1318&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve got it figured out, I just needed to do some calculation to get all the pieces moved correctly.
I need to add another couple tests for en passant on the edge files, one for an EP by black on
white, and a few other cases, but I suspect &lt;code&gt;perft&lt;&#x2F;code&gt; will reveal if there are any such issues.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2117&quot;&gt;2117&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-06-22T21:48:00.245032Z DEBUG perft_start_position_to_depth_6:perft{depth=5}:perft{depth=4}:perft{depth=3}:perft{depth=2}:perft{depth=1}: hazel::game: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 | r . b q k b n r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7 | p . p p p p p p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6 | n P . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5 | . . . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4 | . . . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3 | . . . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 | . P P P P P P P&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 | R N B Q K B N R&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    a b c d e f g h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Black to play&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2024-06-22T21:48:00.245161Z DEBUG perft_start_position_to_depth_6:perft{depth=5}:perft{depth=4}:perft{depth=3}:perft{depth=2}:perft{depth=1}: hazel::game: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 | r . b q k b n r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7 | p . p p p p p p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6 | n P . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5 | p P . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4 | . . . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3 | . P . . . . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 | . . P P P P P P&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 | R N B Q K B N R&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    a b c d e f g h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Black to play&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is where the bug is introduced. In the first Ply, White plays axb6, and in the second Ply, the
&lt;code&gt;unmake&lt;&#x2F;code&gt; function has been called but did not properly accomplish the unmove. By the time we see it,
White has played b3, but the board is in an incorrect state because the en passant didn’t unwind
properly.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not 100% sure what I did wrong, but I think the answer is probably to add a bunch more tests.&lt;&#x2F;p&gt;
&lt;p&gt;One thing I could do is have each ply have a pointer to a ‘previous’ ply, rather than maintaining a
full history in the ply itself. This would trivialize the &lt;code&gt;unmake&lt;&#x2F;code&gt; function, but at the cost of way
more memory use (I think).&lt;&#x2F;p&gt;
&lt;p&gt;I think the first step is to analyze the &lt;code&gt;unmake&lt;&#x2F;code&gt; side of the en passant, and make sure it works
consistently. I’m looking forward to when I have the movegen side of this working correctly, so I
can refactor it to be less of a giant megamethod, I think at least some of my pain is found there.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>21-JUN-2024</title>
        <published>2024-06-21T00:00:00+00:00</published>
        <updated>2024-06-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/21-jun-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/21-jun-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/21-jun-2024/">&lt;h2 id=&quot;1610&quot;&gt;1610&lt;&#x2F;h2&gt;
&lt;p&gt;Working on getting this fixed up and functional, I updated dependencies, cleaned up some syntax
stuff, got a &lt;code&gt;flake&lt;&#x2F;code&gt; set up and &lt;code&gt;rustfmt&lt;&#x2F;code&gt; configured and running. I’ll add precommits at some point
maybe.&lt;&#x2F;p&gt;
&lt;p&gt;I’m working on the pgn parsing issue, it appears to be failing to generate blocking moves for check.
It gets stuck on 26. .. Rf7 in the example fixture at tests&#x2F;fixtures&#x2F;no-variations.pgn. The &lt;code&gt;perft&lt;&#x2F;code&gt;
test is also over-counting the number of moves, so I need to figure out why it isn’t seeing the rook
move.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to check out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;godzie44&#x2F;BugStalker&quot;&gt;bugstalker&lt;&#x2F;a&gt; to see if it helps suss
out what’s happening.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2115&quot;&gt;2115&lt;&#x2F;h2&gt;
&lt;p&gt;I found the issue. I think my movegen was more or less fine? I added some logic about looking for
‘blocking squares’, but I don’t actually know if it’s necessary. I’ll have to come back and test it
when I get to the refactor stage. Right now I’ve chased down a different bug which appears to be due
to &lt;code&gt;Game::from_fen&#x2F;1&lt;&#x2F;code&gt; not calculating metadata from the FEN string. It ultimately delegates to
&lt;code&gt;Ply::from_fen&#x2F;1&lt;&#x2F;code&gt;, which appears to incorrectly grant castling rights to black, which is incorrect.
I suspect this is because &lt;code&gt;Metadata::default()&lt;&#x2F;code&gt; grants castling rights, but in the event I see the
&lt;code&gt;-&lt;&#x2F;code&gt; value, I don’t do anything, which means it breaks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2133&quot;&gt;2133&lt;&#x2F;h2&gt;
&lt;p&gt;I got everything pushed up onto &lt;code&gt;main&lt;&#x2F;code&gt;, switched the branch over, and need to just do a few more
cleanup tasks before I can set the repo to open.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2147&quot;&gt;2147&lt;&#x2F;h2&gt;
&lt;p&gt;Added a LICENSE (AGPLv3), README, and uncommented the next tier of &lt;code&gt;perft&lt;&#x2F;code&gt;, which is failing due to
unimplemented &lt;code&gt;EP_CAPTURE&lt;&#x2F;code&gt; in the &lt;code&gt;src&#x2F;ply&#x2F;make.rs&lt;&#x2F;code&gt; module.&lt;&#x2F;p&gt;
&lt;p&gt;For now, it’s good enough to go live I think. I still need to chase out some dependabot warnings,
but that shouldn’t be too hard&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>3-JUN-2024</title>
        <published>2024-06-03T00:00:00+00:00</published>
        <updated>2024-06-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/3-jun-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/3-jun-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/3-jun-2024/">&lt;h2 id=&quot;1041&quot;&gt;1041&lt;&#x2F;h2&gt;
&lt;p&gt;I’m in between meetings so I did some cleanup and got the benches working again. I’m going to wipe
out the old results and start fresh this evening.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2-JUN-2024</title>
        <published>2024-06-02T00:00:00+00:00</published>
        <updated>2024-06-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/2-jun-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/2-jun-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/2-jun-2024/">&lt;h2 id=&quot;1457&quot;&gt;1457&lt;&#x2F;h2&gt;
&lt;p&gt;Took a brief break to work on some &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jfredett&#x2F;katuv&quot;&gt;other stuff&lt;&#x2F;a&gt;, and will
probably continue to do so for a bit, but I &lt;em&gt;also&lt;&#x2F;em&gt; looked a bit at
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;EmbarkStudios&#x2F;rust-gpu&quot;&gt;rust-gpu&lt;&#x2F;a&gt; and I think there is a natural way to
translate the montgomery stuff to use that, so I may take a brief stab at implementing my MMP
solution there instead of via SIMD. If I could get this to run on a GPU I suspect I’d sweep the
speedrun targets pretty quickly, and it’s a good way to get a pipeline set up to exploit the GPU for
other similar problems.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>31-MAY-2024</title>
        <published>2024-05-31T00:00:00+00:00</published>
        <updated>2024-05-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/31-may-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/31-may-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/31-may-2024/">&lt;h2 id=&quot;0802&quot;&gt;0802&lt;&#x2F;h2&gt;
&lt;p&gt;I got this all working last night and started it on my R730, Dragon-of-Perdition. It is not fast,
and it is not yet producing results I would feel confident counting on, but it is running and broke
past the Berndt-Galway% barrier overnight.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, the next step is to work on improving the solver speed and that means SIMD.&lt;&#x2F;p&gt;
&lt;p&gt;I will later need to build up another layer above the broker (or move some of the broker stuff down
to another thread, IDK yet), to allow for some cross-system coordination; but for now I can scale to
consume all available cores on a machine and that is pretty rad.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been thinking about how to SIMD and I’m leaning towards the MMP solution with SIMD happening
within the MMP implementation. I considered trying to SIMD across primes, and that might still be
the ‘right’ way (more on that in a second) in some sense, but ultimately I want to build an
upgradable thing for &lt;em&gt;all&lt;&#x2F;em&gt; numbers, and that’ll work better with MMP.&lt;&#x2F;p&gt;
&lt;p&gt;I think it’ll also scale better to GPUs.&lt;&#x2F;p&gt;
&lt;p&gt;I’d like to build something that is a sort of ‘progressive’ multiprecision, so slowly expanding the
amount of SIMD resources spent on the multiprecision-ness, but also allowing for a SIMD-ified &lt;code&gt;Elt&lt;&#x2F;code&gt;
object, which means we’d have SIMD both &lt;em&gt;inside&lt;&#x2F;em&gt; the object and ‘across’ the object. Essentially
having a &lt;code&gt;EltVector&amp;lt;R_EXP, WIDTH&amp;gt;&lt;&#x2F;code&gt; where &lt;code&gt;WIDTH&lt;&#x2F;code&gt; is the number of MP objects contained in the
structure, which can then be vectorized as well. Not quite sure how to make that happen just yet,
but one of the things my current implementation does which I think might not be so clever as I hoped
is calculate a range of primes for each chunk that is ‘just outside’ the range. This seems to result
in a lot of ‘near misses’ where the high watermarks on passing items is frequently 40+ primes. I
can’t tell if that’s a bug or if the choice of primes are such that this is ‘normal’.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, each chunk publishes the range of primes used to calculate it. Unfortunately it doesn’t
currently print what the start&#x2F;span is, so another area to improve is the reporting and general
output functionality.&lt;&#x2F;p&gt;
&lt;p&gt;I think chosing primes at the start may be net faster, as I should, in principle, be able to cache
and share the Montgomery &lt;code&gt;Space&lt;&#x2F;code&gt; objects across everything as immutable objects and eliminate some
amount of churn when spinning up new threads. I suspect that’ll be quicker and will give more
consistent results. If I set it to read those primes from a file I should be able to exactly
replicate some results which should help me verify my code is working equivalently to the prior
work.&lt;&#x2F;p&gt;
&lt;p&gt;This also opens some alternative Speedrun categories in the form of ‘what’s the set of primes for
which the number of passed tests is minimized in the worst case?’&lt;&#x2F;p&gt;
&lt;p&gt;That question is actually extremely interesting once you try asking &lt;em&gt;why&lt;&#x2F;em&gt; those primes might result
in a minimized NSW passed-tests metric.&lt;&#x2F;p&gt;
&lt;p&gt;I also think the ‘how many tests did you actually pass’ metric is a little harder on me than it has
been on prior work, since I’m always testing across all 60 primes, where I believe they only tested
across as many as it took to get a NSW. So prior works ‘maximum passed tests’ might be hiding the
fact that the tests were run sequentially, and they just ‘lucked out’ and had most terminate early,
the alternative prime modes should support that model of checking as well.&lt;&#x2F;p&gt;
&lt;p&gt;So, the TODO list as it stands, in no particular order:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Improve report output to include:
&lt;ul&gt;
&lt;li&gt;SHA of code used to run it&lt;&#x2F;li&gt;
&lt;li&gt;Timestamp of start time, duration information&lt;&#x2F;li&gt;
&lt;li&gt;Range searched&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Extract broker’s RX Loop to a separate thread&lt;&#x2F;li&gt;
&lt;li&gt;Build multi-broker coordinator&lt;&#x2F;li&gt;
&lt;li&gt;Implement alternative prime-selection modes
&lt;ul&gt;
&lt;li&gt;Existing mode finds primes via miller rabin&lt;&#x2F;li&gt;
&lt;li&gt;Also support providing a list of primes
&lt;ul&gt;
&lt;li&gt;preinclude prime lists from all prior work&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Also support sequential scan&#x2F;short circuiting vs full test mode&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;SIMDify an MMP implementation
&lt;ul&gt;
&lt;li&gt;This is, y’know, pretty hard&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I think that covers it, I’m going to continue to let it run on my other machine, but at the moment
it looks to be doing about 4-5 billion values per day, so I’ve got a long way to go to beat the
~5 month time &lt;code&gt;jhg&lt;&#x2F;code&gt; set.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1213&quot;&gt;1213&lt;&#x2F;h2&gt;
&lt;p&gt;I killed the run on my other machine, the 2,3 search wasn’t converging particularly nicely, and I
think I’ll probably need to adjust my approach, it will help when the reciever loop is independent
of the main loop, so that all my control logic is separate from my output&#x2F;adjustment logic and solve
logic.&lt;&#x2F;p&gt;
&lt;p&gt;I managed to get up to around 1e10 in about 12 hours, so I’m within spitting distance of Matson%.&lt;&#x2F;p&gt;
&lt;p&gt;I want to improve the report output as it seems to be the lowest hanging fruit, and improving it
should help me come up with a better time-tuning algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;I may try just refactoring to use an existing BigInt instead of u128, and maybe my existing impl
will translate cleanly, not sure yet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>30-MAY-2024</title>
        <published>2024-05-30T00:00:00+00:00</published>
        <updated>2024-05-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/30-may-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/30-may-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/30-may-2024/">&lt;h2 id=&quot;2042&quot;&gt;2042&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, I did a bunch of work to start implementing the parallelized version of this. Yes, I am
putting off learning the SIMD stuff. I’m trying to sort out the right way to vectorize it, and I
haven’t decided if I want to try to just outscale the pain in performance that comes w&#x2F; the MMP
branch, or if I want to try to just knock out &lt;code&gt;2^64%&lt;&#x2F;code&gt;[1]. I’m leaning MMP but I have to make sure
I’ve got that dog in me.&lt;&#x2F;p&gt;
&lt;p&gt;So, naturally I turn to the other thing, parallelization.&lt;&#x2F;p&gt;
&lt;p&gt;I have mostly implemented the thing, but I’m chasing the borrow-checker around and I need to work
out how this thing is going to function.&lt;&#x2F;p&gt;
&lt;p&gt;I want to make sure that if the program crashes, I can recover with minimal lost work. We can see
why in a bit from &lt;code&gt;jhg&lt;&#x2F;code&gt;’s work, they note:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We tested the first 1x10^15 (1 quadrillion) values over a period of ~5 months (January-May, 2020),
but no additional solutions were found.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;5 months is a long time, and indeed the time will grow exponentially for me. I’m attacking that
problem through scaling out, but I also need to consider how often I want to spend ‘saving’ the
work I’ve already done so that I don’t waste it in an unexpected crash.&lt;&#x2F;p&gt;
&lt;p&gt;I also want to be able to upgrade this over time, I’m going to be continuing to run this well past
the initial &lt;code&gt;2^64%&lt;&#x2F;code&gt; goal, so I want to be able to reliably stop without wasting work. My plan is to
build to the point where I have &lt;em&gt;some&lt;&#x2F;em&gt; implementation going that can reliably generate new NSWs as
quickly as possible, so that I can then slowly iterate and replace parts as it runs.&lt;&#x2F;p&gt;
&lt;p&gt;To accomplish this, I really want to think in terms of an RPO, not in terms of how it’s going to
work; if I never want to lose more than some target time – say a minute – of data, then it’s easy
enough to break off a ‘chunk’ of my target range and search it; identifying some set of primes just
outside the range dynamically, it can employ any number of algorithms for searching that range that
it likes, so long as I record:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The primes used&lt;&#x2F;li&gt;
&lt;li&gt;The number of solutions&#x2F;nonsolutions in the range&lt;&#x2F;li&gt;
&lt;li&gt;The SHA of the version of code being run, so we can replicate it after the fact&lt;&#x2F;li&gt;
&lt;li&gt;Build information (dependencies, etc) associated with the code&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;A future skeptic could then check out the same code at the same versions, compile the code, and with
reasonable certainty replicate the chunk.&lt;&#x2F;p&gt;
&lt;p&gt;I’d conjecture that larger chunks will generally be more efficient, but smaller chunks are safer
from a crash-perspective. Because I also expect to scale to new hardware in this process, I won’t
always know how large of a range will take a minute to process, so ultimately I want to have some
dynamic ‘tuning’ capability.&lt;&#x2F;p&gt;
&lt;p&gt;Since I’m already breaking things into chunks, it makes sense to me to have a Broker&#x2F;Worker design
to fan this work out across cores. The ‘broker’ hands out ‘chunks’ to the ‘spans’ along with some
primes that are just slightly outside the span. I’m not sure that’ll make things faster, but it’s
very aesthetic.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve roughed in a version of that, but it’s still missing a couple pieces.&lt;&#x2F;p&gt;
&lt;p&gt;First, I’m pretty sure as written it’ll only run one thread; but I was fighting a lot with the
borrow checker and wanted to get to some psuedo-stable point.&lt;&#x2F;p&gt;
&lt;p&gt;Second, I haven’t implemented the ‘take_primes’ function which should return a fixed number of
primes upon request.&lt;&#x2F;p&gt;
&lt;p&gt;I have a lot of ideas for optimizations, but I want to get to the point where I can start running
this in some capacity and start figuring out how to upgrade it in situ.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;[1] An footnote: I am going to name some things.&lt;&#x2F;p&gt;
&lt;p&gt;First, an acronym: WNS or NSW, both mean &lt;code&gt;Witness of Nonsolution&lt;&#x2F;code&gt; or &lt;code&gt;Nonsolution-Witness&lt;&#x2F;code&gt;. These
are the primes for which the Legendre test returns a non-residue result.&lt;&#x2F;p&gt;
&lt;p&gt;Second, I’m going to assign some ‘speedrun’ categories to different bounds. The obvious ones are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Gupta% : Wall time to 63&lt;&#x2F;li&gt;
&lt;li&gt;Berndt-Galway% : Wall time to 1e9&lt;&#x2F;li&gt;
&lt;li&gt;Matson% : Wall time to 1e12&lt;&#x2F;li&gt;
&lt;li&gt;jhg% : Wall time to 1e15&lt;&#x2F;li&gt;
&lt;li&gt;2^64% : Wall time to solve for every value less than 2^64&lt;&#x2F;li&gt;
&lt;li&gt;Brocard% : Time To Novel Proof there are&#x2F;are no more solutions.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Other categories may be introduced in the future. I have assigned names as seem appropriate, the
first person to set a record in the category should, I think, have a right to name it, so if any of
these fine folks want to change the name I’m happy to oblige as official self-nominated benevolent
record-keeper for as long as the position suits me.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you for coming to my footnote.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>26-MAY-2024</title>
        <published>2024-05-26T00:00:00+00:00</published>
        <updated>2024-05-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/26-may-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/26-may-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/26-may-2024/">&lt;h2 id=&quot;1223&quot;&gt;1223&lt;&#x2F;h2&gt;
&lt;p&gt;I have two big problems:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Get an ASM dump of the montgomery math to verify there are no divisions.&lt;&#x2F;li&gt;
&lt;li&gt;SIMDify montgomery math.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;For #2, I think the actual algorithm isn’t really SIMD friendly until I’m doing MP, but some of the
math functions might need some attention. I’m going to look over the C++ code from the prior work to
see if I can glean how they approached it, but my suspicion is that the SIMD will really come in on
the brocard side of the problem, not the montgomery side.&lt;&#x2F;p&gt;
&lt;p&gt;I could potentially SIMD to do some calculations in parallel, but I don’t think it’ll gain much.&lt;&#x2F;p&gt;
&lt;p&gt;The ASM dump to verify no divisions is a bit more straightforward. The #new code definitely has at
least a couple divisions by &lt;code&gt;r&lt;&#x2F;code&gt;, but I should be able to replace them w&#x2F; &amp;amp;’s. There’s a &lt;code&gt;% n&lt;&#x2F;code&gt; in
there as well but I don’t think that’s going anywhere.&lt;&#x2F;p&gt;
&lt;p&gt;I replaced the &lt;code&gt;r&lt;&#x2F;code&gt; divisions and kicked off the benchmark, I expect little gain.&lt;&#x2F;p&gt;
&lt;p&gt;I’m going to refactor the montgomery math to use const generics for R_EXP, and then refactor the
benchmark to try every relevant R_EXP. The &lt;code&gt;redc&lt;&#x2F;code&gt; algorithm currently has to recalculate &lt;code&gt;r-1&lt;&#x2F;code&gt;
every time, and a const R_EXP would prevent that. It might also be worth genericizing over &lt;code&gt;u128&lt;&#x2F;code&gt; to
see if a u64 is faster.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1256&quot;&gt;1256&lt;&#x2F;h2&gt;
&lt;p&gt;One way I might approach SIMDing the montgomery stuff is SIMDing the &lt;code&gt;.enter&lt;&#x2F;code&gt; side, and having a
single &lt;code&gt;n&lt;&#x2F;code&gt; and constant &lt;code&gt;R&lt;&#x2F;code&gt; for the space. So that a single Space can handle, e.g., &lt;code&gt;Cache - Overhead&lt;&#x2F;code&gt; values.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1424&quot;&gt;1424&lt;&#x2F;h2&gt;
&lt;p&gt;Refactoring to a const R_EXP appears to have improved things slightly, at least on Legendre symbol
benchmarking. Many of the benchmarks don’t scale nicely to const generics so it’s a little tricky to
tell. Next step is to refactor out the u128, but that is going to be a massive effort since every
math function relies on u128 and will need to be tweaked.&lt;&#x2F;p&gt;
&lt;p&gt;Refactoring that should transparently support SIMD-lanes, which would probably improve the existing
BrocardSpan implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Overally there is a ~1-2% improvement from the R_EXP refactor, which is pretty good for such a small
change. Avoiding the extra calculations on each &lt;code&gt;redc&lt;&#x2F;code&gt; should pay off significantly on the brocard
benchmark. I’ll run that next to see how it goes. I would expect to reap significant benefit since
&lt;code&gt;redc&lt;&#x2F;code&gt; is run on each multiply, and factorial necessarily multiplies &lt;code&gt;n&lt;&#x2F;code&gt; times, so a &lt;code&gt;1%&lt;&#x2F;code&gt; move on
&lt;code&gt;n&lt;&#x2F;code&gt; multiplies is a &lt;code&gt;1.01^n&lt;&#x2F;code&gt; move on the total time.&lt;&#x2F;p&gt;
&lt;p&gt;I can also consider refactoring &lt;em&gt;just&lt;&#x2F;em&gt; the factorial function to SIMD to see if that adds an extra
bit of speed to brocard.&lt;&#x2F;p&gt;
&lt;p&gt;I also need to refactor TestCase to have a const R_EXP, and then do some more cleanup.&lt;&#x2F;p&gt;
&lt;p&gt;I did finish re-organizing the code, the tests are all still clumped in the &lt;code&gt;montgomery&#x2F;mod.rs&lt;&#x2F;code&gt;
file, I’ll probably pull them out to the &lt;code&gt;tests&lt;&#x2F;code&gt; directory since they’re a little tough to organize
otherwise.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1440&quot;&gt;1440&lt;&#x2F;h2&gt;
&lt;p&gt;I can’t actually refactor the factorial because I can’t use u128 w&#x2F; simd. ugh.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1809&quot;&gt;1809&lt;&#x2F;h2&gt;
&lt;p&gt;Slight &lt;em&gt;regression&lt;&#x2F;em&gt; for brocard, not sure why, really need to look at the ASM output. I suppose it
might be down to the fact that I make a bunch of these &lt;code&gt;Space&lt;&#x2F;code&gt; objects and the cost is in doing some
of the same precalculations over and over? Not sure.&lt;&#x2F;p&gt;
&lt;p&gt;Next step is to Genericize, I think, that’ll at least allow me to process a small range of &lt;code&gt;n&lt;&#x2F;code&gt;’s
simultaneously, if I set it to some generic LANE size I can do some benchmarking to see what the
best size is, but I can relatively cheaply calculate a vector of &lt;code&gt;n_i!&lt;&#x2F;code&gt; over some small range &lt;code&gt;i&lt;&#x2F;code&gt; in
&lt;code&gt;[k, k+LANES]&lt;&#x2F;code&gt; since each &lt;code&gt;n_i = (n_i-1)i&lt;&#x2F;code&gt; which means I calculate &lt;code&gt;n_k!&lt;&#x2F;code&gt; and then each subsequent
element in the range is easily constructed in &lt;code&gt;LANES&lt;&#x2F;code&gt; operations, then I can legendre test all of
them; since each will ‘terminate’ at different times I can just have a &lt;code&gt;LANES&lt;&#x2F;code&gt;-sized mask that I
check to determine when to stop, meaning the Legendre test will take a worst-case time of the
slowest test in the range. I can also short circuit if I get a Non-witness report, since it doesn’t
matter how many it passes, only that it fails on at least one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2305&quot;&gt;2305&lt;&#x2F;h2&gt;
&lt;p&gt;I did some work w&#x2F; &lt;code&gt;flamegraph&lt;&#x2F;code&gt; to chase out some remaining div_mod calls, that worked quite well.&lt;&#x2F;p&gt;
&lt;p&gt;I also found that the fairly naive splattering of &lt;code&gt;rayon&lt;&#x2F;code&gt; primitives around the solve function was
probably resulting in some deadlock or something, because it simply made my machine hot for 30m
while the sequential version runs to 1 billion in ~11m or so. Which, if I were to parallelize it
perfectly efficiently would mean I’m right in the same ballpark as the prior solution in terms of
speed.&lt;&#x2F;p&gt;
&lt;p&gt;One optimization I made that wasn’t simply avoiding div_rem instructions was to avoid a &lt;code&gt;.exit()&lt;&#x2F;code&gt;
call in the Legendre symbol calculation. Since &lt;code&gt;0&lt;&#x2F;code&gt; is the same value for every &lt;code&gt;R&lt;&#x2F;code&gt;, we can just
check for &lt;code&gt;0&lt;&#x2F;code&gt; without leaving montgomery form, and it turns out that &lt;em&gt;entering&lt;&#x2F;em&gt; montgomery form is
faster (despite having more steps) because there are only shifts and multiplies due to &lt;code&gt;redc&lt;&#x2F;code&gt;, so
you can minimize the math by comparing the result to see if it’s equal to &lt;code&gt;space(1)&lt;&#x2F;code&gt;, rather than
&lt;code&gt;exit&lt;&#x2F;code&gt;ing as I was.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>25-MAY-2024</title>
        <published>2024-05-25T00:00:00+00:00</published>
        <updated>2024-05-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/25-may-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/25-may-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/25-may-2024/">&lt;h2 id=&quot;0012&quot;&gt;0012&lt;&#x2F;h2&gt;
&lt;p&gt;Alright, I’ve got a brocard benchmark in place, I’m slow as molasses. I think the next step is
profiling, I don’t want to jump to a SIMD conversion until I’m sure I’ve got the algorithm right.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing that occurs to me to check is the generated code to ensure there aren’t any division
instructions being written. Ultimately, the point of montgomery arithmetic is to dodge divisions by
replacing them with shifts; so I would assume an audit of the generated code to verify there are
only divisions where I think there should be divisions makes sense.&lt;&#x2F;p&gt;
&lt;p&gt;I’m getting this committed, then I’m going to read
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;towardsdatascience.com&#x2F;nine-rules-for-simd-acceleration-of-your-rust-code-part-1-c16fe639ce21&quot;&gt;this&lt;&#x2F;a&gt;,
which seems like an interesting article. Right now, I think there are two paths forward with SIMD.&lt;&#x2F;p&gt;
&lt;p&gt;First, I could rewrite the existing implementation to parameterize it’s &lt;code&gt;Elt&lt;&#x2F;code&gt; type, instead of u128,
it’s be T. I have no idea what effect that’ll have on performance, and I imagine it will deeply
change how much I have to appease the trait system, but I think it’s a theoretical &lt;code&gt;K&lt;&#x2F;code&gt;-times speedup for
essentially a bunch of gruntwork when I sub in &lt;code&gt;u64xK&lt;&#x2F;code&gt; or whatever it is. The downside is this
cannot exceed some value slightly below 2^64, since I’ll need primes larger than &lt;code&gt;n&lt;&#x2F;code&gt;, and those
primes have to be represented as a 64b number to make good use of SIMD in this model. I don’t see
any 128b types allowed in the docs I’ve looked at, but I haven’t looked particularly hard since
&lt;code&gt;signac-vector&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Second, I could focus on something past the &lt;code&gt;2^64 (~1e19)&lt;&#x2F;code&gt; barrier. While it is 4 orders of
magnitude ahead, and it took months to go from 1e12 to 1e15, I am approaching this with a scaling
game in mind; I’m honestly not all that interested in Brocard itself, I’m interested in building out
the thing that scales the solution and making that efficient, so it may be wise to focus on the
multiprecision brocard implementation. That should be easy to make SIMD&#x2F;vectorizing friendly, to the
point where I would expect most of the relevant loops to be vectorized by the compiler. A naive
(not explicitly SIMDified) implementation would obviate the barrier and also potentially be
sufficiently quick (with the added horsepower I have) to not hinder progress.&lt;&#x2F;p&gt;
&lt;p&gt;Multiprecision is also the way to go for GPU implementation, which is still somewhere in the cards.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, the final thing I need to do is some cleanup in the repo, get things organized, tests
moved to their rightful place, some documentation work, and hopefully by the time I’m done I’ll feel
like figuring out performance tracing for what feels like the thousandth time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0038&quot;&gt;0038&lt;&#x2F;h2&gt;
&lt;p&gt;Reading this article was a very good idea, SIMD does not work the way I thought it did anymore.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0052&quot;&gt;0052&lt;&#x2F;h2&gt;
&lt;p&gt;Finished reading (well, skimming through) the article. I think I know the approach, the answer is
‘both’. I can optimize the existing algorithm using this new &lt;code&gt;core::simd&lt;&#x2F;code&gt; stuff mentioned in the
article to get familiar with it. This will allow me to hit &lt;code&gt;2^61 - 1&lt;&#x2F;code&gt; as my largest prime, with
&lt;code&gt;R_EXP=61&lt;&#x2F;code&gt;. That’s about 1e18, or 3 orders of magnitude from the previous attempt.&lt;&#x2F;p&gt;
&lt;p&gt;Next, I’ll implement a multiprecision montgomery version using SIMD while the initial version is
running. The algorithm with generate Brocard Spans and dump all the relevant metadata to disk.
Periodically they will run the same span to verify they are both producing the same result. I think
the managing apparatus will just be a couple systemd-wrapping-sinatra or something to drive them and
report results to some parent process I can run on toto.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>21-MAY-2024</title>
        <published>2024-05-21T00:00:00+00:00</published>
        <updated>2024-05-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/brocards-problem/21-may-2024/"/>
        <id>https://disturbed-circles.com/log/brocards-problem/21-may-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/brocards-problem/21-may-2024/">&lt;h2 id=&quot;1555&quot;&gt;1555&lt;&#x2F;h2&gt;
&lt;p&gt;Current status: Hauling ass.&lt;&#x2F;p&gt;
&lt;p&gt;I set up a brocard run up to 1e9, as an initial test. It’s currently quite a bit slower than the jhg
version, but I think for an unoptimized bit of hackery it’s doing alright. &lt;code&gt;rayon&lt;&#x2F;code&gt; is handling
parallelizing, but it’s the stupidest implementation I could come up with so I think there’s more to
gain by just improving the code a bit.&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned above, there’s an outer loop that’s causing a lot of slowness on the inner loop by
recalculating factorial over and over. I’m also not being particularly efficient with how I break up
work. I should be controlling the work-unit size and assigning threads to a smaller sub-span of
whatever input span I get.&lt;&#x2F;p&gt;
&lt;p&gt;I can then precompute all the relevant montgomery spaces, and share some of the work of calculating
the factorial of all those spaces.&lt;&#x2F;p&gt;
&lt;p&gt;I suppose since each number is only 16B wide, if I plan to precompute all the factorials for a given
range, then the total memory allocation is only &lt;code&gt;16*(UPPER_BOUND - START)&lt;&#x2F;code&gt;. If I split off the
parent range into ‘sections’, I can probably manage the memory use and then simply precompute the
factorial for the whole range, then iterate over each to do the series of legendre tests,
essentially turning the loop inside out and saving all that time.&lt;&#x2F;p&gt;
&lt;p&gt;I need to set up proper benchmarks for that, and probably learn a bit more about Rayon.&lt;&#x2F;p&gt;
&lt;p&gt;I also need to look into SIMD optimization for this, but it’s limited inasmuch as I want to use 128b
values in most places, but nothing appears to support lanes &amp;gt;64b.&lt;&#x2F;p&gt;
&lt;p&gt;I want to push the boundary to arbitrary heights, but I suppose refactoring the existing impl to at
least by type-generic might be worth it if it doesn’t hurt performance. It may be faster to cover
all 64b numbers first, then move to a multi-precision model which will be slower but can proceed
unbounded.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>8-JAN-2024</title>
        <published>2024-01-08T00:00:00+00:00</published>
        <updated>2024-01-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://disturbed-circles.com/log/hazel/8-jan-2024/"/>
        <id>https://disturbed-circles.com/log/hazel/8-jan-2024/</id>
        
        <content type="html" xml:base="https://disturbed-circles.com/log/hazel/8-jan-2024/">&lt;h2 id=&quot;1541-ui&quot;&gt;1541 - ui&lt;&#x2F;h2&gt;
&lt;p&gt;I took some time to write a little Actor-adjacent (I don’t think these &lt;em&gt;technically&lt;&#x2F;em&gt; qualify as proper actors, but
whatever) system for &lt;code&gt;Hazel&lt;&#x2F;code&gt; to use, it should be enough to separate out the communication logic from the chess logic,
which I hope will make it easier to finally get it done. It also supports an open ended ‘message’ system. To implement a
new message, a struct implements &lt;code&gt;MessageFor&amp;lt;W&amp;gt;&lt;&#x2F;code&gt; where &lt;code&gt;W&lt;&#x2F;code&gt; is, in theory, a &lt;code&gt;Witch&lt;&#x2F;code&gt; backend, but could be whatever if I
want to create a new engine later. The &lt;code&gt;Witch&lt;&#x2F;code&gt; type is a little message reactor machine thing. It’s somewhere between a
genserver, SmallTalk object, Ruby class, and twisted nightmare that only the damned may dream of.&lt;&#x2F;p&gt;
&lt;p&gt;I used to be a ruby guy, so I’ll let you guess where I got the inspiration.&lt;&#x2F;p&gt;
&lt;p&gt;In any case, the next step is to refactor the Driver to use this backend, and that means extracting out the stateful
bits from the communicating bits.&lt;&#x2F;p&gt;
&lt;p&gt;One other tidbit about the design is that the request and response types are separate. The response type is arbitrary
because I explicitly &lt;em&gt;did not&lt;&#x2F;em&gt; include a general way to get at a Witch’s state object (which is also arbitrary) from the
Handle that controls it. I don’t want to make an assumption about how one should interact with their state, and very
often returning a whole object would be silly anyway. Messages do not generally allow for direct response (although such
a thing could be encoded in a message type easily to bypass the built in &lt;code&gt;write&lt;&#x2F;code&gt; mechanism), all output from the Actor
is through the broadcast channel. It’s assumed every client will want to recieve every message in lockstep.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t intend to really have more than one or two of these at present, though I could see using this as a stepping
stone towards multiple separate instances across multiple machines, all communicating. Ultimately my goal was to learn
&lt;code&gt;tokio&lt;&#x2F;code&gt;, and I think I’ve got it to hand now. Reasoning about it is tricky for sure, but it honestly just reminds me of
Haskell, it’s just a matter of understanding how the laziness works and then chasing the compiler around until
everything type and borrowchecks.&lt;&#x2F;p&gt;
&lt;p&gt;It’s a pretty nice system, I am interested to eventually investigate &lt;code&gt;tower&lt;&#x2F;code&gt; for this or another project, but time will
tell.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1901-ui&quot;&gt;1901 - ui&lt;&#x2F;h2&gt;
&lt;p&gt;I’m thinking a bit about refactoring the tests. I think I’d like to break out of the habit of writing the tests in the
same file; it makes the files quite large, and I much prefer lots of small files, even if it means jumping around some
more. I suspect I’ll want to add some editor shortcuts for alternating between test and source files, and maybe also add
in some kind of shortcut for running relevant benchmarks as well, not quite sure how I’ll do that, but when the time
comes.&lt;&#x2F;p&gt;
&lt;p&gt;In any case. I think I’m going to look towards centralizing and better codifying the tests I have, and once I have
something that can, ostensibly, play chess, I’ll probably take the time to move to &lt;code&gt;rstest&lt;&#x2F;code&gt; and get something with good
coverage and few mutants. I generally aim to have the testing part of the codebase be 1&#x2F;3rd to 1&#x2F;2 the total size of the
codebase, and I’m sitting close to the 1&#x2F;2 mark, so I definitely want to take some time to build something that can be
extended naturally and easily.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
