<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="https://riceball.com/wp-content/plugins/pretty-rss-feeds/xslt/pretty-feed.xsl" type="text/xsl" media="screen" ?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Thaura - 🍙</title>
	<atom:link href="https://riceball.com/tag/thaura/feed/" rel="self" type="application/rss+xml" />
	<link>https://riceball.com</link>
	<description></description>
	<lastBuildDate>Sat, 31 Oct 2026 02:29:07 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>

<image>
	<url>https://riceball.com/wp-content/uploads/sites/2/2025/10/onigiri-150x150.png</url>
	<title>Thaura - 🍙</title>
	<link>https://riceball.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 5</title>
		<link>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/</link>
					<comments>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 02:24:19 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31271</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" fetchpriority="high" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p><p>Code profiling tools are everything now. When I was staring at Thaura writing code, it was doing some wild tricks with python and grep and other unix tools that I&#8217;d never seen before. So I told it to write tools to do simple kinds of code analysis, to help map out and index the code. [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 5</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Code profiling tools are everything now.</p>



<p class="wp-block-paragraph">When I was staring at Thaura writing code, it was doing some wild tricks with python and grep and other unix tools that I&#8217;d never seen before.</p>



<p class="wp-block-paragraph">So I told it to write tools to do simple kinds of code analysis, to help map out and index the code. I also wrote scoreboard database tools, to keep track of work to do, and work completed. I had it put the code analysis info into the database, too.</p>



<p class="wp-block-paragraph">I also asked it to tell me about all the PHP static analysis tools, and enlisted them all into the programming process: linters, code stylers, static type analysis.</p>



<p class="wp-block-paragraph">The LLM can use these tools the way we use them, to understand the code, and to demonstrate that code conforms to some idea of &#8220;order&#8221;.</p>



<p class="wp-block-paragraph">The LLM also uses them as a kind of debugging aid, or a pre-run tester.</p>



<p class="wp-block-paragraph">I also leaned on Playwright and the old reliable PHPUnit.</p>



<h2 class="wp-block-heading">Illusions of Complete Coverage, and &#8220;AI Psychosis&#8221;</h2>



<p class="wp-block-paragraph">The problem with these code analysis tools is: they don&#8217;t enforce writing good code as much as assist with it. They mainly help when the code is big enough to forget parts of it.</p>



<p class="wp-block-paragraph">They give you the illusion of total control, when you&#8217;re just keeping things together.</p>



<p class="wp-block-paragraph">Likewise, the LLM will appear to be making great, sweeping changes over the code, <em>but touching only a fraction of it</em>, leaving lots of code untouched, and <em>report back with a chat message that it did a lot of work</em>.</p>



<p class="wp-block-paragraph"><strong>The LLM straight up bullshitted the boss!</strong></p>



<p class="wp-block-paragraph">I totally fell for it.</p>



<p class="wp-block-paragraph">The problems would trigger errors and warnings, and then the LLM would look at the errant code, and go fix it, with some chatter about how <strong>it was still doing the old thing</strong>, when it should be doing the <strong>new thing</strong>.</p>



<p class="wp-block-paragraph">Then it was fixed, passed the test, looks good in the analysis tools, and the LLM moved on, and I moved on.</p><p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 5</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-5/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 4</title>
		<link>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/</link>
					<comments>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 00:31:01 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31246</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p><p>Continuing the series, more info about altering project internals. I think of this like a caterpillar going into a cocoon, having enzymes totally disintegrate its guts, and then produce a butterfly, which will go out and mate with other butterfiles. It&#8217;s a metamorphosis. Except, with this software, you don&#8217;t see any visible changes once it&#8217;s [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 4</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Continuing <a href="https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/">the series</a>, more info about altering project internals.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">I think of this like a caterpillar going into a cocoon, having enzymes totally disintegrate its guts, and then produce a butterfly, which will go out and mate with other butterfiles. It&#8217;s a metamorphosis. Except, with this software, you don&#8217;t see any visible changes once it&#8217;s changed.</p>



<p class="wp-block-paragraph">So that&#8217;s not a good analogy.</p>



<p class="wp-block-paragraph">Maybe it&#8217;s more like an electric car, which looks as ugly as the gasoline cars, or even worse, but has completely different insides. It&#8217;s better on the inside.</p>



<p class="wp-block-paragraph">Another bad analogy.</p>



<p class="wp-block-paragraph">It&#8217;s like you shoved a seed into a pile of manure, and it&#8217;s started to grow, but you still can&#8217;t see the plant. It just looks like a pile of shit. But there&#8217;s good stuff in there.</p>



<p class="wp-block-paragraph">Yes, that&#8217;s it.</p>
</blockquote>



<p class="wp-block-paragraph">I&#8217;m going to do another release of software.</p>



<p class="wp-block-paragraph">I&#8217;ll just call it r2 or release 2&#8230;.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Here&#8217;s what happened. It took all day. The reasons were noted in the email I sent out, but the actual delays were as follows:</p>



<p class="wp-block-paragraph">The instructions that the LLM wrote were not easy to understand. In retrospect, I should have just hand-written them.</p>



<p class="wp-block-paragraph">(Then, those notes could have become part of the LLMs knowledge, and could have influenced it to write better documents.)</p>



<p class="wp-block-paragraph">Cloning the database was smooth, but getting the live database container updated to a newer version of MariaDB took extra time.</p>



<p class="wp-block-paragraph">Cloning the release from Git was quick. Moving it into place was quick. (Name the new clone directory blahblah.new, then mv blahblah to blahbla.old, then mv blahblah.new blahblah. Restart Nginx, restart the php container.)</p>



<p class="wp-block-paragraph"><strong>Configuring the Nginx proxy took a LOT of effort, because I did it too soon. The examples the LLM created were wrong, as well, but had enough info that I could make it work</strong>.</p>



<p class="wp-block-paragraph">Reconfiguring the containers to run the app was pretty simple, but I had forgotten that I changed the paths where I wanted the files mounted. This sent me down some rabbitholes related to Nginx config. (I should have held back on changing Nginx.)</p>



<p class="wp-block-paragraph">Overall, it wasn&#8217;t that bad, except for the Nginx configuration.</p>



<h3 class="wp-block-heading">A New, Nonfunctional API</h3>



<p class="wp-block-paragraph">I made an API to feed the mobile app, and it didn&#8217;t work. Digging into the code, was a minor horror. The LLM wrote code well, but the overall &#8220;separation of concerns&#8221; and keeping the code in the right places, wasn&#8217;t so great.</p>



<p class="wp-block-paragraph">I forget what the fix was, but it eventually worked. It was a combination of fixing some obsolete SQL code, and making an Nginx config.</p>



<h2 class="wp-block-heading">PHP Attack Scripts</h2>



<p class="wp-block-paragraph">The PHP security hole drama has led to a bit more attack against the sites, particularly <a href="https://riceball.com/2026/10/29/hackscripts-patterns/">scans for remote shells written in PHP</a>.</p>



<p class="wp-block-paragraph">That just overloads the server, even when the scripts aren&#8217;t there.</p>



<p class="wp-block-paragraph">So I had to do some tricks to detect these requests, and block them. This took a few hours.</p>



<h3 class="wp-block-heading">Get Rid of phpinfo()</h3>



<p class="wp-block-paragraph">If  you&#8217;re running PHP in a container, and use .env to pass passwords into your container, it&#8217;s critical to find and remove all instances of scripts that use the phpinfo() function.</p>



<p class="wp-block-paragraph">That function dumps the environment variables to the page, leaking credentials. This command will recursively find the string &#8220;phpinfo&#8221; in all your files.</p>


<pre class="wp-block-code"><span><code class="hljs">grep -r phpinfo *</code></span></pre>


<h2 class="wp-block-heading">Archives</h2>



<p class="wp-block-paragraph">One of my big goals was to get the site into shape for archving. This entails being able to easily download the entire site, using tools like wget.</p>



<p class="wp-block-paragraph">Generating HTML files as final output is one step toward this goal. While archivers handle .php file endings, they like .html more, and with .html, you can view archives with a plain web browser.</p>



<p class="wp-block-paragraph">With .html files, you can &#8220;archive&#8221; by copying over all the files. You won&#8217;t need all this software to operate the archived site.</p>



<h3 class="wp-block-heading">Indexes</h3>



<p class="wp-block-paragraph">Generating complete indexes to the news articles and events allows webcrawlers to get at everything.</p>



<p class="wp-block-paragraph">This is also a risk, because lots of bots are out there scraping the site, and a complete index will potentially increase their downloading, and risk overloading the site.</p>



<p class="wp-block-paragraph">Page generation helps with this, because serving up a generated HTML page takes a tiny fraction of the resources of running a PHP file. (Example: on an older computer, a very heavy site like WordPress can top out at 30 requests per second, while a similar HTML site can reach into the 10k requests per second.)</p>



<p class="wp-block-paragraph">Bots I&#8217;ve seen scraping the site: Google, Bing, Claude, Baidu, OpenAI, Ahrefs, Yandex.</p>



<h3 class="wp-block-heading">Twig Templates</h3>



<p class="wp-block-paragraph">To this end, instead of trying to change the page generation within the existing code, I had the LLM add Twig. It seemed to know more about Twig than Blade, so I went with Twig.</p>



<p class="wp-block-paragraph">The LLM set up a parallel template structure that copied parts of the existing templates, and then ported the entire site to use it, but didn&#8217;t actually remove all of it, because some of the templates we had were full of PHP code.</p>



<p class="wp-block-paragraph">The Twig templates mixed with the old template system are a mess; they&#8217;re completely enmeshed, to replicate the old site. </p>



<p class="wp-block-paragraph">Eventually, almost the entire site will be generated with Twig.</p>



<p class="wp-block-paragraph">Eventually, this will be replaced with new layouts that aren&#8217;t mixed with the old code.</p>



<p class="wp-block-paragraph">I suspect I&#8217;m going to need to start the process by hand, writing my own templates.</p>



<h3 class="wp-block-heading">Order and Memory Capacity</h3>



<p class="wp-block-paragraph">This did get me thinking about the issue of why we think some code is well organized, and some code is not.</p>



<p class="wp-block-paragraph">Part of it is our limited capacity to comprehend large, complicated systems.</p>



<p class="wp-block-paragraph">To handle big systems, we use structures, like lists, hierarchies, &#8220;black boxing&#8221;, making things modular, and using repetitive patterns.</p>



<p class="wp-block-paragraph">The LLM, unlike people, has a different kind of &#8220;memory&#8221; or &#8220;attention&#8221; or capacity to deal with large amounts of information. So, while the code looks like a mess to me, it still makes sense to the LLM.</p>



<p class="wp-block-paragraph">Here&#8217;s some computer code that vibe coding produced:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#F8F8F2;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>function rotated(p){ // rotate cells 90deg clockwise, re-normalize to 0
  const maxX = Math.max(...p.cells.map(c=>c.x));
  const cells = p.cells.map(c=>({x:c.y, y:maxX-c.x, ch:c.ch}));
  const minX = Math.min(...cells.map(c=>c.x)), minY = Math.min(...cells.map(c=>c.y));
  return cells.map(c=>({x:c.x-minX, y:c.y-minY, ch:c.ch}));
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">function</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">rotated</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">p</span><span style="color: #F8F8F2">){ </span><span style="color: #6272A4">// rotate cells 90deg clockwise, re-normalize to 0</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> maxX </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Math.</span><span style="color: #50FA7B">max</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">p.cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">c.x));</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> cells </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> p.cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">({x</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.y, y</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">maxX</span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2">c.x, ch</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.ch}));</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> minX </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Math.</span><span style="color: #50FA7B">min</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">c.x)), minY </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Math.</span><span style="color: #50FA7B">min</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">c.y));</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">return</span><span style="color: #F8F8F2"> cells.</span><span style="color: #50FA7B">map</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2">({x</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.x</span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2">minX, y</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.y</span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2">minY, ch</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">c.ch}));</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Almost any programmer has written code like that, but how many enjoy <em>reading</em> code like that.</p>



<p class="wp-block-paragraph">Conversely, computer code is extremely brittle. A single character out of place, and parts may break. The LLM can write code, but more importantly, it can transform vague instructions and turn them into concrete goals, like people can. So it&#8217;s like a programming language that&#8217;s a human language.</p>



<p class="wp-block-paragraph">The challenge is to get the LLM to conform to (the declining) human need to keep code organized, for human comprehension.</p><p>The post <a href="https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 4</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/30/thaura-porting-legacy-php5-and-php7-project-to-php8-part-4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 3</title>
		<link>https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/</link>
					<comments>https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 28 Oct 2026 04:12:07 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31239</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p>Continuing the series, more info about altering project internals. I got so tired that I stopped blogging. A note to myself read: The main big issues I&#8217;ve hit this time are refactoring introducing bugs bug repairs introducing bugs incomplete testing of outputs database export and import problems. Refactoring Introducing Bugs Initially, I wasn&#8217;t that aggressive [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 3</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Continuing <a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">the series</a>, more info about altering project internals.</p>



<p class="wp-block-paragraph">I got so tired that I stopped blogging. A note to myself read:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">The main big issues I&#8217;ve hit this time are refactoring introducing bugs bug repairs introducing bugs incomplete testing of outputs database export and import problems.</p>
</blockquote>



<h2 class="wp-block-heading">Refactoring Introducing Bugs</h2>



<p class="wp-block-paragraph">Initially, I wasn&#8217;t that aggressive about testing. I just used URLs and GET to test a list of pages, and told the bot to read the logs. It would find errors and warnings, and fix them.</p>



<p class="wp-block-paragraph">Then, I got hit with a bunch of uncaught bugs.</p>



<p class="wp-block-paragraph">One of them was a bug that I knew we corrected before.</p>



<p class="wp-block-paragraph">So I decided that whenever I found a bug, I wanted a test generated that would prevent that bug from reappearing.</p>



<p class="wp-block-paragraph">I&#8217;m guessing that a bug reappeared because the code was being <a href="https://en.wikipedia.org/wiki/Code_refactoring" target="_blank" rel="noopener">refactored</a>.</p>



<p class="wp-block-paragraph">Refactoring is basically building a new code structure, and then copying your old code into it. When it copied the code, it wrote the bug back into existence.</p>



<h2 class="wp-block-heading">Bug Fixing Revealing Bugs or Introducing Bugs</h2>



<p class="wp-block-paragraph">This isn&#8217;t an LLM issue per-se, but in dynamic languages, fixing a bug might reveal other bugs that, until then, were not found, because the first bug killed the program.</p>



<p class="wp-block-paragraph">An automated test case helps with these.</p>



<h2 class="wp-block-heading">Incomplete Testing of Outputs</h2>



<p class="wp-block-paragraph">I wish I could remember the situation, but Thaura did a big batch of changes, but it wasn&#8217;t testing the output. It just did the modifications.</p>



<p class="wp-block-paragraph">Some early modifications had automated tests, and it used those to fine tune it&#8217;s behavior, but then, it just abandoned testing.</p>



<p class="wp-block-paragraph">It seemed to be working so fast, so I asked if it was checking outputs. It wasn&#8217;t.</p>



<p class="wp-block-paragraph">So, it&#8217;s good to ask the bot what it did. You can read it, and determine if the bot failed to do something. You can find tune its behavior.</p>



<h2 class="wp-block-heading">Database Import and Export Problems</h2>



<p class="wp-block-paragraph">Initially, I tried to do <strong>a mysqldump from MySQL 5.7 and load it into MariaDB 11</strong>. It didn&#8217;t work, but I expected that. Not only that, but the data needed a lot of manual cleanup.</p>



<p class="wp-block-paragraph">So I used an intermediate format, JSON, to dump the data, and load it in. That worked extremely well.</p>



<p class="wp-block-paragraph">Then, I thought I could dump from the dev database and load it into the production database, like this:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="342" height="509" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-01-14.png?wsr" alt="" class="wp-image-31242" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-01-14.png 342w, https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-01-14-202x300.png 202w" sizes="auto, (max-width: 342px) 100vw, 342px" /></figure>



<p class="wp-block-paragraph">No such luck. </p>



<p class="wp-block-paragraph">They were both MariaDB 11, and the same point version, but different releases, and in slightly different operating systems (Alpine Linux vs. whatever MariaDB&#8217;s Docker package uses).</p>



<p class="wp-block-paragraph">So I had Thaura write a filter to allow the dump to work, mainly by stripping some comments, like this:</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="386" height="647" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-04-59.png?wsr" alt="" class="wp-image-31243" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-04-59.png 386w, https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-27-21-04-59-179x300.png 179w" sizes="auto, (max-width: 386px) 100vw, 386px" /></figure>



<p class="wp-block-paragraph">(Claude screwed up the diagram. The first dump is a MySQL dump.)</p>



<p class="wp-block-paragraph">Obviously, I should have focused on defining an intermediate data dump format that would work for us.</p>



<p class="wp-block-paragraph">This isn&#8217;t a PHP porting issue, but it could come up.</p><p>The post <a href="https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 3</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/27/thaura-porting-legacy-php5-and-php7-project-to-php8-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 2</title>
		<link>https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/</link>
					<comments>https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 24 Oct 2026 03:39:22 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31223</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p>Last time it was about updating code. Now it&#8217;s about altering project internals. Mid-Project Legacy A long time ago, I decided that the old style include(&#8216;foo_class.inc&#8217;) was annoying, and the new style autoloader classes with use \Foo; were nicer. So I did a simple thing: copy them all into a namespace, and then convert them [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 2</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">Last time it was about <a href="https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/">updating code</a>. Now it&#8217;s about altering project internals.</p>



<h2 class="wp-block-heading">Mid-Project Legacy</h2>



<p class="wp-block-paragraph">A long time ago, I decided that the old style include(&#8216;foo_class.inc&#8217;) was annoying, and the new style autoloader classes with use \Foo; were nicer.</p>



<p class="wp-block-paragraph">So I did a simple thing: copy them all into a namespace, and then convert them to PSR-4 compatible classes (aka, autoloading classes).</p>



<p class="wp-block-paragraph">I left the old files around, just in case they were still being used. The project never completed, and maybe around 10 classes were converted, and many were not.</p>



<p class="wp-block-paragraph">I told the LLM to fix this, and make everything into a PSR-4 compatible class. It decided which version was good, and which was not and possible merges.</p>



<p class="wp-block-paragraph">This is mind-blowing to me, that the program can do this.</p>



<p class="wp-block-paragraph">The process took a day, due to pauses and usage limits, and I&#8217;m still not sure it&#8217;s OK.</p>



<p class="wp-block-paragraph">The goal here was to allow static code checking tools like Psalm to do better code analysis.</p>



<h3 class="wp-block-heading">So far, no real new code</h3>



<p class="wp-block-paragraph">I&#8217;m just writing this to make a weird point: I haven&#8217;t asked the LLM to write new code. It&#8217;s refactoring.</p>



<p class="wp-block-paragraph">It&#8217;s making old code conform to newer programming standards.</p>



<p class="wp-block-paragraph">It&#8217;s removing code, too.</p>



<h3 class="wp-block-heading">Some Removals</h3>



<p class="wp-block-paragraph"><strong>Reporting bad posts</strong> &#8211; a system similar to Digg, where the community can moderate. It stopped being useful when people gamed it or it didn&#8217;t instantly mod someone down.</p>



<p class="wp-block-paragraph"><strong>Spam trapping</strong> &#8211; I had a bunch of filters, some quite nice, but it was out of date.</p>



<p class="wp-block-paragraph"><strong>IP logging and redirecting</strong> &#8211; this is still important, but the site&#8217;s implementation was pretty annoying, so it goes.</p>



<p class="wp-block-paragraph"><strong>DIY captcha</strong> &#8211; I wrote it because there weren&#8217;t many options I liked. Now, it&#8217;s not that relevant because there are packages for captchas.</p>



<p class="wp-block-paragraph"><strong>Themes</strong> &#8211; again, not super popular, and it was done in a annoying way, with GET parameters.</p>



<p class="wp-block-paragraph">These removals aren&#8217;t all because the feature was bad, but it was just out of date, or should be replaced. Removing them helped reduce the code size.</p>



<h2 class="wp-block-heading">Improving Debugging</h2>



<p class="wp-block-paragraph">After telling Thaura to do something a certain way, over and over, it starts to do it, automatically, and even expand on it.</p>



<p class="wp-block-paragraph">I told it to use the static analysis and dependency databases a couple times, and it figured out how to use them.</p>



<p class="wp-block-paragraph">I told it to always do static analysis and check dependencies, and it would do both, with the tools, and on its own.</p>



<p class="wp-block-paragraph">So every change is checked with these tools, and also with the Playwright integration tests against some URLs. These can trigger warnings in the logs, so I have it read the logs and debug error and warning messages.</p><p>The post <a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 2</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 1</title>
		<link>https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/</link>
					<comments>https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 22:21:35 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=31203</guid>

					<description><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p>This document describes how I&#8217;m porting a legacy PHP codebase to PHP8.5. The security crisis of October 2026 required porting everything on a legacy website to PHP8, the only version that&#8217;s getting updated now. This document is in flux and will change as the port progresses. The legacy code was running on two containers, behind [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 1</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1280" height="1280" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1.jpg 1280w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-300x300.jpg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-1024x1024.jpg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-150x150.jpg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/10/malignant-internet-commenters-abusing-each-other-i1-768x768.jpg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p><p class="wp-block-paragraph">This document describes how I&#8217;m porting a legacy PHP codebase to PHP8.5. The security crisis of October 2026 required porting everything on a legacy website to PHP8, the only version that&#8217;s getting updated now. This document is in flux and will change as the port progresses.</p>



<p class="wp-block-paragraph">The legacy code was running on two containers, behind a nginx reverse proxy, that directed most of the traffic to he PHP7 version of the code, but ran some very old code in PHP5.</p>



<p class="wp-block-paragraph">The goal was to port code to PHP8, and implement a new app stack that&#8217;s nginx + php-fpm + php8.5.</p>



<p class="wp-block-paragraph">The TL;DR:</p>



<ul class="wp-block-list">
<li>Lean on code linters first.</li>



<li>Create infrastructure to organize the process of fixing individual files, to get them to compile. Don&#8217;t bother to fix the logic at this time.</li>



<li>Tell the LLM to log changes.</li>



<li>Build up the new codebase from the old (the LLM made this decision), linting the old PHP7 code mostly.</li>



<li>Build up the new deployment environment by using the old config files.</li>
</ul>



<p class="wp-block-paragraph">The general progression of the work:</p>



<ol class="wp-block-list">
<li>Download all the old code into a project.
<ol class="wp-block-list">
<li>Make a git repo, and add lines to README to use it. (Helps the LLM undo things and see history.)</li>



<li>Include relevant config files. (Teaches context. LLM should know all the parts, rather than assume anything.)</li>



<li>Create careful database dumps, by table rather than the entire db. I had an old archiving tool for this, and used it. Download into repo.</li>



<li>Write notes about the current architecture, project folder layout, db version.</li>



<li>Tell the LLM to log changes to a changelog.</li>
</ol>
</li>



<li>Update the code so it compiles.
<ol class="wp-block-list">
<li>Use static code linters, stylers, deprecated code scanners, etc. to test the code. (Do not rely on the LLM&#8217;s reasoning. Ask it to recommend tools, and install them. Then, you need to configure them to work with your file layout, include paths, etc.)</li>



<li>Let the LLM plan and make the code changes.</li>



<li>Let the LLM guess about which files, and which versions, would need to be ported.</li>



<li>The LLM had trouble running a batch script to do the tool calls, so I told it to make another batcher script to run the script over around 20 files. The LLM tells me to run it when it&#8217;s changed.</li>



<li>Made mid-project decision to use a SQLite scoreboard to track the state of each file. Updated scripts to update the scoreboard. This makes the batching partially obsolete.</li>
</ol>
</li>



<li>Make a Docker dev environment similar to the deployment goal. Use this to do the runtime integration tests.
<ol class="wp-block-list">
<li>Playwright for integration testing.</li>



<li>PHPUnit or similar for unit or function testing.</li>
</ol>
</li>
</ol>



<h2 class="wp-block-heading">The llm</h2>



<p class="wp-block-paragraph">I&#8217;m using Thaura Pro. The pro is that it&#8217;s pretty cheap at $15 a month. The problem is that you can use it only 5 hours at a time, and then you have to take a break. I really don&#8217;t mind this.</p>



<p class="wp-block-paragraph">The tool execution limit will trigger every 15 minutes or so, and require a button click.</p>



<h2 class="wp-block-heading">Static Checkers</h2>



<p class="wp-block-paragraph">Linters and static code checkers run on the desktop computer to produce reports about code problems. <strong>These help you analyze lots of code without burning tokens (or dealing with the indeterminacy of LLMs</strong>).</p>



<p class="wp-block-paragraph">The LLM should write the config files for these tools, so it can adjust them as it runs.</p>



<p class="wp-block-paragraph">I started with report text files, and a batch file to produce them, but eventually added a sqlite based scoreboard to track work progress. The linting can happen in parallel with the LLM coding.</p>



<p class="wp-block-paragraph">Coding is &#8220;slow&#8221;, at maybe 1 minute per file. That&#8217;s many multiples of how fast I code, but there is still some waiting. The LLM works in batches of 5-10 files.</p>



<p class="wp-block-paragraph">A batch checker script, over time, became a kind of scratchpad for the next 10 to 20 files to test. Due to a security issue, I had to run this manually.</p>



<p class="wp-block-paragraph">What&#8217;s nice about the scoreboard and the report.txt sidecars is that I can work in parallel with the LLM. I just write tools (by hand, or by LLM), use other LLMs to set up Docker, edit the README and other notes.</p>



<p class="wp-block-paragraph">Even this static analysis phase is full of constant changes and improvements.</p>



<h2 class="wp-block-heading">The Port Environment</h2>



<p class="wp-block-paragraph">The initial environment is a directory that looks like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">src/
     db/ -- legacy data
     apache/ -- legacy config
     nginx/ -- legacy config
     php5/ -- legacy code
     php7/ -- legacy code
     php8/ -- ported code, goes into git repo
         sitename/ -- not the actual sitename
             local/ -- caches and local code
             public/ -- website root
             shared/ -- project-wide code libraries
bin/ -- scripts and tools to help <span class="hljs-keyword">with</span> coding, goes <span class="hljs-keyword">in</span> repo
docker/ -- configs and tools <span class="hljs-keyword">for</span> docker containers, goes <span class="hljs-keyword">in</span> repo
legacy-data/ -- not the actual name, but things like generated files, temp files, uploads, were downloaded into here, <span class="hljs-keyword">as</span> samples. The entire site was not copied.
</code></span></pre>


<p class="wp-block-paragraph">The main tools (at thist time) are syntax checkers, linters, like &#8216;php -l&#8217;, phpstan, psalm, phpcs. Helper scripts run the tools, load configs, query the scoreboard, etc.</p>



<p class="wp-block-paragraph">Thaura can also run these tools individually.</p>



<p class="wp-block-paragraph">Changes are logged in these places: CHANGELOG.txt, somescript.php.report.txt sidecars that record the output of the syntax checkers (so the LLM doesn&#8217;t need to run them individually), the git commits, and I write some changes into README.txt and then tell Thaura to read it. I think Thara also keeps a todo file on its server.</p>



<p class="wp-block-paragraph">Legacy configs help a lot, explaining how the actual live app works. Porting proceeds breadth-first, and based on what&#8217;s exposed through these configs, particularly the nginx reverse proxy, which forwards traffic to two different PHP containers, depending on the URI.</p>



<p class="wp-block-paragraph">The new config is much simpler, because it&#8217;s a single codebase. The old configs help the port avoid porting stray PHP files here and there, by identifying what is exposed to the world.</p>



<p class="wp-block-paragraph">Early on, the LLM is just guessing which files are dependencies. This will come out in the wash and rinse as the code is executed.</p>



<h2 class="wp-block-heading">Code Fixing</h2>



<p class="wp-block-paragraph">The first goal was to get all the code compiling. I didn&#8217;t care if it had some warnings, and <strong>I didn&#8217;t care if it even ran correctly</strong>.</p>



<p class="wp-block-paragraph">This took over a day, but eventually finished.</p>



<p class="wp-block-paragraph">Initially, I thought the next step would be to write tests, like TDD, but, instead, the LLM was going into actual debugging, so I went along.</p>



<p class="wp-block-paragraph">This is almost like the opposite of TDD, and more like interactive programming with an interpreter.</p>



<p class="wp-block-paragraph">I&#8217;d give it a URL, and tell it to fix it, by figuring out which files get loaded, and checking the work from the URL down to the libraries. It required checking dependencies.</p>



<h3 class="wp-block-heading">Tests</h3>



<p class="wp-block-paragraph">So I did around 10 or 15 of these debugging excursions, and it got better at it over time.</p>



<p class="wp-block-paragraph">Next, I told it to create Playwright tests for a bunch of the URLs, and some new ones.</p>



<p class="wp-block-paragraph">More on this later.</p>



<h2 class="wp-block-heading">Database Tables</h2>



<p class="wp-block-paragraph">During debugging, it would sometimes hit missing database tables. This could cause the LLM to go on a pointless debugging excursion, or try to recreate the table.</p>



<p class="wp-block-paragraph">I&#8217;d have to stop it, ssh into the server, alter the table dumping script, exit ssh, and then do an rsync to copy the new table dumps.</p>



<p class="wp-block-paragraph">The LLM created a couple utilities to upload the tables into the local DB.</p>



<h3 class="wp-block-heading">MySQL 5.7 to MariaDB Migration</h3>



<p class="wp-block-paragraph">Initially, I thought it would work to use the db dumps to load MariaDB. It seemed like some python scripts could fix them up, since they use roughly the same SQL.</p>



<p class="wp-block-paragraph">I hadn&#8217;t thought about the long term nightmare of migrating from latin1 to utf8, which the site underwent over many years. By and large, the data was ASCII or UTF-8, but many columns were typed as latin1.</p>



<p class="wp-block-paragraph">So, instead, the LLM offered to fix some of the bad data, and I asked for tools to dump the data to JSON, and load the data from JSON.</p>



<p class="wp-block-paragraph">The new tables and columns will, eventually, be utf8mb4, or whatever is best for the near future.</p>



<p class="wp-block-paragraph">The data repair was pretty amazing. It didn&#8217;t just fix our internal migration mistakes &#8211; it also fixed dirty user input.</p>



<p class="wp-block-paragraph">I could tell it had the accumulated experience of decades of annoyances people had when migrating to Unicode and UTF8.</p>



<h2 class="wp-block-heading">Testing URLs</h2>



<p class="wp-block-paragraph">The LLM seemed to be really good at figuring out how a URL maps to a PHP file, and all the PHP files that get involved in producing that URL.</p>



<p class="wp-block-paragraph">I also taught it how to go into the /admin/ area, with a username and password, and run the page generation code.</p>



<p class="wp-block-paragraph">The code wasn&#8217;t really working, so during this &#8220;training&#8221;, it was also looking at the code and fixing it until it worked. Mostly, it was configuration issues.</p>



<p class="wp-block-paragraph">So, now, I could tell it to fix something that involved page generation, and it could &#8220;drive&#8221; the site to regenerate the page during its debugging.</p>



<p class="wp-block-paragraph">I settled into using this prompt pattern:</p>


<pre class="wp-block-code"><span><code class="hljs">/path/to/url.php -- this page does this, but it's not doing it correctly. Debug it.
</code></span></pre>


<p class="wp-block-paragraph">I repeated this for all the parts of the admin, including the parts I was hoping to remove.</p>



<p class="wp-block-paragraph">Then I repeated it for world-facing pages.</p>



<p class="wp-block-paragraph">I didn&#8217;t test if the site could upload files, etc. When I was creating the Playwright tests, it went ahead and wrote tests to do some of that.</p>



<p class="wp-block-paragraph">So, with this interactive debugging, I suspect I primed the LLM to know how to make the Playwright tests.</p>



<h2 class="wp-block-heading">Simplification by Replacing Variables with Constants</h2>



<p class="wp-block-paragraph">The site had two config files, and many of the configs were global variables.</p>



<p class="wp-block-paragraph">Most of these were used like constants. They never changed.</p>



<p class="wp-block-paragraph">So I told two LLMS to go, one by one, and replace the variable with a constant, if the variable wasn&#8217;t ever assigned a value elsewhere in the code.</p>



<p class="wp-block-paragraph">Every variable is a potential decision point: an if statement, or switch statement, or concatenation in a string that&#8217;s a file path, etc.</p>



<p class="wp-block-paragraph">Replacing variables with constants, when possible, should make debugging easier.</p>



<p class="wp-block-paragraph">To test it, I used the big test suite in playwright, and told the LLM to run each test individually, and read the logs, fixing any errors or warnings.</p>



<h2 class="wp-block-heading">Enabling Xdebug</h2>



<p class="wp-block-paragraph">I should have done this from the start, but better late than never. I had it produce dumps about what functions got called, and it also allows the LLM to do debugging.</p>



<h2 class="wp-block-heading">Scoreboards and Dependencies</h2>



<p class="wp-block-paragraph">I had it create a scoreboard system to see how the code porting and conversion were progressing &#8212; the pass/fail status was determined by running static checkers on the code.</p>



<p class="wp-block-paragraph">Then I created commands to query the scoreboard.</p>



<p class="wp-block-paragraph">It eventually seemed to use it a little bit. I think doing the scoreboard from the start, could have helped, but, if anything, I got more use out of it than the LLM.</p>



<p class="wp-block-paragraph">I also had it create a database of dependencies, of what files get included (and what files include a given file).</p>



<p class="wp-block-paragraph">Tools for OOP in PHP will produce this info, but this codebase is mostly PHP4 style require() and include() based.</p>



<p class="wp-block-paragraph">Again, I don&#8217;t know if the LLM used it, but it would have helped debugging go faster.</p>



<p class="wp-block-paragraph">This is all debugging infrastructure, ultimately, and it&#8217;s good not only for the LLM but for the programmer as well.</p>



<h2 class="wp-block-heading">Removing Features</h2>



<p class="wp-block-paragraph">The old software had a bunch of features that nobody seems to use anymore.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-Deja-Vu-Mono.ttf" style="font-size:.875rem;font-family:Code-Pro-Deja-Vu-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#F8F8F2;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>going forward, i want to do a commit before, and a dev release after, a site feature is removed, so it's easy to go back and undo a bad batch of work. for example, for this round, I'd like to remove code related to themes, theme.php and anything related to it, like CSS files, any gui related to the theme, and logic to switch the theme. Only the default theme should be left. analyze the code, plan the removal, and then remove, and test. then, remove any playwright tests for themes. when it's all good, do a dev release.</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F8F8F2">going forward, i want to do a commit before, and a dev release after, a site feature is removed, so it&#39;s easy to go back and undo a bad batch of work. for example, for this round, I&#39;d like to remove code related to themes, theme.php and anything related to it, like CSS files, any gui related to the theme, and logic to switch the theme. Only the default theme should be left. analyze the code, plan the removal, and then remove, and test. then, remove any playwright tests for themes. when it&#39;s all good, do a dev release.</span></span></code></pre></div>



<p class="wp-block-paragraph">I know the codebase pretty well, so I knew this was a pretty simple change.</p>



<p class="wp-block-paragraph">Removing features removes files, and removing files reduces the amount of context required to edit the code.</p>



<p class="wp-block-paragraph">Code that would use the theme variable was also rewritten to simply use the default theme.</p>



<p class="wp-block-paragraph">(My plan is to re-add features by using external libraries when appropriate.)</p>



<p class="wp-block-paragraph"><a href="https://riceball.com/2026/10/23/thaura-porting-legacy-php5-and-php7-project-to-php8-2/">Continued in part 2</a>.</p><p>The post <a href="https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/">Thaura: Porting Legacy PHP5 and PHP7 Project to PHP8 Part 1</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/22/thaura-porting-legacy-php5-and-php7-project-to-php8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Thaura &#038; WordPress: layout advice chatbot</title>
		<link>https://riceball.com/2026/10/08/thaura-wordpress-layout-advice-chatbot/</link>
					<comments>https://riceball.com/2026/10/08/thaura-wordpress-layout-advice-chatbot/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 09 Oct 2026 03:55:48 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Prompts]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30722</guid>

					<description><![CDATA[<p><img width="1024" height="1024" src="https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10.jpeg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10.jpeg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10-300x300.jpeg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10-150x150.jpeg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10-768x768.jpeg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p><p>This bot gives advice about how to make layouts in WordPress using the stock tools and features. More on this later, on to the Thaura Projects settings. Thaura Projects is a feature to allow you to create chatbots (and other interactive tools). To create a new Project, click on Project in the navigation, and then [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/10/08/thaura-wordpress-layout-advice-chatbot/">Thaura & WordPress: layout advice chatbot</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><img width="1024" height="1024" src="https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10.jpeg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10.jpeg 1024w, https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10-300x300.jpeg 300w, https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10-150x150.jpeg 150w, https://riceball.com/wp-content/uploads/sites/2/2026/09/57745157-b626-4bd6-b87d-186358473f10-768x768.jpeg 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p><p class="wp-block-paragraph">This bot gives advice about how to make layouts in WordPress using the stock tools and features. More on this later, on to the Thaura Projects settings.</p>



<p class="wp-block-paragraph">Thaura Projects is a feature to allow you to create chatbots (and other interactive tools).</p>



<p class="wp-block-paragraph">To create a new Project, click on Project in the navigation, and then &#8220;+&#8221; in the upper right corner.</p>



<p class="wp-block-paragraph">Fill in the form with:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td>Title</td><td>WordPress Gutenberg Advice Bot</td></tr><tr><td>Description</td><td>A chatbot that advises how to produce what you want, using the features of the stock wordpress blocks, and the Site Editor features. If it seems difficult to do, then say so.</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Then save it, and go to the Project. In the upper right, click the triple-dot menu and Edit.</p>



<p class="wp-block-paragraph">Add:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td>Project Instructions</td><td>If stuck, review the Core Blocks reference <a href="https://developer.wordpress.org/block-editor/reference-guides/core-blocks/" target="_blank" rel="noopener">https://developer.wordpress.org/block-editor/reference-guides/core-blocks/</a><br>If there&#8217;s no obvious solution read <a href="https://developer.wordpress.org/themes/" target="_blank" rel="noopener">https://developer.wordpress.org/themes/</a> for possible solutions.</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">This is a screenshot of the dialog box where you paste in the prompts.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="461" height="561" src="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-08-21-08-40.png?wsr" alt="" class="wp-image-30726" srcset="https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-08-21-08-40.png 461w, https://riceball.com/wp-content/uploads/sites/2/2026/10/Screenshot-from-2026-10-08-21-08-40-247x300.png 247w" sizes="auto, (max-width: 461px) 100vw, 461px" /></figure><p>The post <a href="https://riceball.com/2026/10/08/thaura-wordpress-layout-advice-chatbot/">Thaura & WordPress: layout advice chatbot</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/10/08/thaura-wordpress-layout-advice-chatbot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Adapting Traditional OOP Style to the LLM World</title>
		<link>https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/</link>
					<comments>https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 30 Sep 2026 02:45:29 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30654</guid>

					<description><![CDATA[<p>(Another Thaura Work product. Again, haven&#8217;t checked, but lots of good ideas in here.) New ways to use old structures to help LLMs write better code. Techniques to reduce token use, reduce context size, reduce errors. Adapting Traditional OOP Style Classic object-oriented design — inheritance hierarchies, polymorphic dispatch, encapsulated state — predates LLMs by decades. [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/">Adapting Traditional OOP Style to the LLM World</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">(Another Thaura Work product. Again, haven&#8217;t checked, but lots of good ideas in here.)</p>



<p class="wp-block-paragraph">New ways to use old structures to help LLMs write better code. Techniques to reduce token use, reduce context size, reduce errors.</p>



<h2 class="wp-block-heading">Adapting Traditional OOP Style</h2>



<p class="wp-block-paragraph">Classic object-oriented design — inheritance hierarchies, polymorphic dispatch, encapsulated state — predates LLMs by decades. Much of what made OOP ergonomic for humans (deep class trees, implicit constructor injection, framework-managed lifecycles) introduces exactly the kind of <em>implicit decisions</em> that hurt one-shot generation. The good news: you can keep the spirit of OOP while stripping out the parts that confuse a model.</p>



<h3 class="wp-block-heading">Inheritance → Composition + Interfaces</h3>



<p class="wp-block-paragraph">Deep <code>extends</code> chains force the model to track overridden methods across multiple files, guess which superclass field is shadowing which, and infer initialization order. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Prefer interfaces / traits / protocols over base classes.</strong> A flat <code>interface PaymentProcessor { process(order: Order): Result }</code> gives the model a complete contract in one place. No diamond problems, no super-call ordering to reason about.</li>



<li><strong>Use composition for shared behavior.</strong> Mixins, embedded structs, or trait implementations (<code>impl Display for MyType</code>) are self-contained blocks the model can generate without knowing the rest of the hierarchy.</li>



<li><strong>If you must inherit, keep depth ≤ 2.</strong> One concrete base + one leaf is manageable; three levels with abstract intermediates start to exceed what the model tracks reliably in a single pass.</li>
</ul>



<h3 class="wp-block-heading">Encapsulation → Explicit Data Structures</h3>



<p class="wp-block-paragraph">Private fields with getters/setters hide data flow behind method calls the model must predict. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Expose plain data structures</strong> (structs, records, frozen objects) at boundaries. The model sees the shape directly instead of inferring it from accessor pairs.</li>



<li><strong>Reserve methods for behavior</strong>, not for field access. If a &#8220;method&#8221; just returns a field, make the field public (or readonly) and delete the getter. Fewer indirection layers means fewer places the model can invent a nonexistent accessor.</li>



<li><strong>Make mutability intentional and visible.</strong> A struct with all-public fields communicates &#8220;data container.&#8221; A class with private state and mutating methods signals &#8220;behavior owner.&#8221; Mixing both in one type forces the model to guess the invariant.</li>
</ul>



<h3 class="wp-block-heading">Polymorphism → Tagged Unions + Pattern Matching</h3>



<p class="wp-block-paragraph">Runtime dynamic dispatch (<code>obj.handle()</code> where the actual type depends on construction site) requires the model to enumerate every possible subclass. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Replace runtime polymorphism with sum types + exhaustive match</strong> wherever the set of cases is closed. <code>enum Shape { Circle(f64), Rect(f64, f64) }</code> matched in one function is unambiguous; a <code>Shape</code> interface with ten subclasses scattered across modules is not.</li>



<li><strong>For open-ended extensibility</strong> (plugin systems, event handlers), use an explicit registry or visitor pattern rather than relying on the model to discover all overrides. The registry is a single lookup table the model can read.</li>



<li><strong>Sealed hierarchies beat open ones.</strong> If the compiler enforces exhaustiveness (Kotlin <code>sealed</code>, Scala sealed, TypeScript discriminated unions), the model knows the case list is complete. Open hierarchies invite phantom branches.</li>
</ul>



<h3 class="wp-block-heading">Dependency Injection → Explicit Constructor Parameters</h3>



<p class="wp-block-paragraph">Frameworks that inject dependencies via annotations, reflection, or container magic hide the dependency graph. The model can&#8217;t see what a class actually needs until it reads the DI configuration. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Pass dependencies through constructors explicitly.</strong> <code>fn new(db: &amp;Pool, cache: &amp;Cache)</code> is visible at the call site. <code>@Inject</code> annotations require reading a separate wiring file the model may not have in context.</li>



<li><strong>Keep constructor arity low (≤ 4).</strong> Beyond that, bundle related deps into a config/options struct. Long parameter lists are where models drop arguments or swap types.</li>



<li><strong>Avoid builder-pattern fluency for core types.</strong> Fluent builders (<code>new Widget().red().big().build()</code>) scatter construction logic across chained calls. A single constructor call with a struct literal is easier to generate correctly.</li>
</ul>



<h3 class="wp-block-heading">Framework Magic → Plain Entry Points</h3>



<p class="wp-block-paragraph">Spring beans, Rails controllers, Angular decorators, and similar frameworks interpose lifecycle hooks, serialization, and routing logic between your code and its observable behavior. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Isolate framework glue in thin adapters.</strong> Keep business logic in plain functions/classes with no framework annotations. The adapter translates HTTP request → function call → response. The model generates the interesting part (logic) without needing to satisfy framework constraints simultaneously.</li>



<li><strong>Prefer functional entry points for pure computation.</strong> A controller that calls <code>calculate_total(items, discount_code)</code> is testable and generatable independently of the web framework. Embedding that calculation inside a decorated class method couples two concerns the model must get right at once.</li>



<li><strong>Document the framework contract in the prompt if unavoidable.</strong> If the target code must be a Spring <code>@Service</code> or a React component, include one minimal working example in the prompt. One concrete exemplar reduces hallucination more than any amount of prose description.</li>
</ul>



<h3 class="wp-block-heading">State Machines → Enum-Driven Flows</h3>



<p class="wp-block-paragraph">Implicit state held in boolean flags (<code>isLoading</code>, <code>hasError</code>, <code>isSubmitted</code>) creates combinatorial explosion the model struggles to navigate. Adaptation:</p>



<ul class="wp-block-list">
<li><strong>Model explicit states as enums.</strong> <code>enum CheckoutState { Idle, FillingCart, ValidatingPayment, Processing, Complete(Error?) }</code> makes invalid transitions impossible and gives the model a finite, named space to work in.</li>



<li><strong>Transition functions take <code>(state, event) → new_state</code>.</strong> Pure transition functions are trivially verifiable and easy to generate. Mutating a stateful object&#8217;s internal booleans is not.</li>



<li><strong>Guard clauses over nested conditionals.</strong> <code>match state { Idle => ..., Processing => ... }</code> beats four levels of <code>if (flag1 &amp;&amp; !flag2 || flag3)</code> that the model must untangle.</li>
</ul>



<h3 class="wp-block-heading">Summary Checklist</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Classic OOP habit</th><th>LLM-friendly adaptation</th><th>Why it helps</th></tr></thead><tbody><tr><td>Deep inheritance tree</td><td>Interface + composition, depth ≤ 2</td><td>Flat contracts, no shadow tracking</td></tr><tr><td>Private fields + getters</td><td>Public/frozen data structs</td><td>Visible shape, no invented accessors</td></tr><tr><td>Runtime polymorphism</td><td>Sum types + exhaustive match</td><td>Closed case set, compiler-checked</td></tr><tr><td>Annotation-based DI</td><td>Explicit constructor params</td><td>Dependency graph visible at call site</td></tr><tr><td>Builder pattern</td><td>Single constructor + options struct</td><td>One expression, not a chain</td></tr><tr><td>Framework-decorated logic</td><td>Thin adapter + pure core function</td><td>Separates concerns the model handles independently</td></tr><tr><td>Boolean-flag state</td><td>Enum-driven state machine</td><td>Finite named states, pure transitions</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">The overarching principle is the same as the rest of this article: <strong>remove implicit decisions</strong>. Traditional OOP optimizes for human maintainability in large teams over years — hiding internals, deferring binding, distributing behavior across a hierarchy. LLM one-shot generation optimizes for a different constraint: everything relevant must be visible, local, and unambiguous within a single context window. You don&#8217;t abandon OOP thinking; you flatten it so the model doesn&#8217;t have to reconstruct the hidden architecture from fragments.</p><p>The post <a href="https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/">Adapting Traditional OOP Style to the LLM World</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/29/adapting-traditional-oop-style-to-the-llm-world/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Language Characteristics that Help LLMs Write Better Code</title>
		<link>https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/</link>
					<comments>https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 02:19:57 +0000</pubDate>
				<category><![CDATA[Human Learning]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30651</guid>

					<description><![CDATA[<p>(Written by Thaura Work. I haven&#8217;t checked it. I&#8217;ve been learning Elm, so there might be some bias it picked up somewhere in my files.) A quick-reference list of language features and conventions that make one-shot code generation more reliable. The common thread: predictability. Features that appear frequently in training data, parse unambiguously, and leave [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/">Language Characteristics that Help LLMs Write Better Code</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">(Written by Thaura Work. I haven&#8217;t checked it. I&#8217;ve been learning Elm, so there might be some bias it picked up somewhere in my files.)</p>



<p class="wp-block-paragraph">A quick-reference list of language features and conventions that make one-shot code generation more reliable. The common thread: <strong>predictability</strong>. Features that appear frequently in training data, parse unambiguously, and leave few implicit choices produce fewer hallucinations and fewer subtle bugs.</p>



<h2 class="wp-block-heading">Type System &amp; Static Structure</h2>



<ul class="wp-block-list">
<li><strong>Explicit type annotations.</strong> Languages with strong static typing (TypeScript, Rust, Go, Java) constrain the solution space dramatically. An annotation like <code>fn process(input: Vec&lt;u8&gt;) -&gt; Result&lt;String, Error&gt;</code> tells the model exactly what goes in and comes out, eliminating an entire class of guessing.</li>



<li><strong>Algebraic / sum types.</strong> Enums, tagged unions, sealed classes, and <code>Result&lt;T, E&gt;</code> force exhaustive handling. The model can&#8217;t silently forget a case the way it can with a bare integer or string status code.</li>



<li><strong>Optionality made explicit.</strong> <code>Option&lt;T&gt;</code>, nullable markers, or required-field syntax prevent &#8220;did I check for null?&#8221; ambiguity from leaking into generated logic.</li>
</ul>



<h2 class="wp-block-heading">Naming &amp; Conventions</h2>



<ul class="wp-block-list">
<li><strong>Descriptive, conventional identifiers.</strong> Names that follow community norms (<code>getUserName</code>, not <code>gn()</code>) match high-frequency patterns in training data. The model essentially autocomplete-s from convention.</li>



<li><strong>Standard library names used as-is.</strong> Reaching for <code>collections.defaultdict</code> instead of inventing a helper keeps the output verifiable and familiar.</li>
</ul>



<h2 class="wp-block-heading">Syntax Predictability</h2>



<ul class="wp-block-list">
<li><strong>Uniform function/method call syntax.</strong> Consistent <code>f(x)</code> across the language means the model rarely fumbles call shapes. Languages mixing macro invocations, operator overloading, and special dispatch forms are harder to get right blind.</li>



<li><strong>No hidden mutation or side effects baked into syntax.</strong> Properties, getters/setters, and overloaded operators introduce behavior the model must infer. Plain functions and plain fields are safer bets.</li>



<li><strong>Single, obvious control-flow forms.</strong> One canonical <code>for x in items:</code> loop beats five dialects. When a language has many ways to express the same thing, the model picks whichever was most frequent in its slice of training data — which may not be your house style.</li>
</ul>



<h2 class="wp-block-heading">Module &amp; Import Clarity</h2>



<ul class="wp-block-list">
<li><strong>Explicit imports.</strong> Languages where every symbol must be imported (Go, ES modules, Rust <code>use</code>) give the model a clear contract. Implicit global namespaces increase the chance of name collisions and wrong-symbol guesses.</li>



<li><strong>Flat, predictable module paths.</strong> Deep dynamic import chains are harder for the model to resolve correctly than shallow, named ones.</li>
</ul>



<h2 class="wp-block-heading">Error Handling</h2>



<ul class="wp-block-list">
<li><strong>Structured errors over exceptions-as-control-flow.</strong> Returning error values or using typed result types is easier for the model to wire up correctly than try/catch ladders with implicit propagation.</li>



<li><strong>One idiomatic recovery path.</strong> If the ecosystem has a single accepted pattern (e.g., Rust&#8217;s <code>?</code> operator), the model converges on it reliably.</li>
</ul>



<h2 class="wp-block-heading">Immutability &amp; Data Flow</h2>



<ul class="wp-block-list">
<li><strong>Default-immutability languages</strong> (Rust ownership, immutable-by-default JS bindings via <code>const</code> discipline, Clojure values) reduce the state-space the model must track. Fewer aliasing surprises mean fewer off-by-one-mutation bugs.</li>



<li><strong>Pure-function-friendly design.</strong> Functions whose output depends only on inputs are trivially composable and easy for the model to reason about step by step.</li>
</ul>



<h2 class="wp-block-heading">Formatting &amp; Tokenization Friendliness</h2>



<ul class="wp-block-list">
<li><strong>Consistent whitespace-based structure</strong> (Python indentation, standard 4-space blocks) maps cleanly onto token boundaries. Irregular formatting or mixed-indentation legacy code increases noise.</li>



<li><strong>Common delimiters and punctuation.</strong> Braces, parentheses, semicolons used uniformly tokenize predictably; exotic delimiter schemes add risk.</li>
</ul>



<h2 class="wp-block-heading">Testability Surface</h2>



<ul class="wp-block-list">
<li><strong>Small, independently callable units.</strong> A language/ecosystem where you can unit-test a function without bootstrapping a framework gives the model a natural stopping point and makes verification cheap.</li>



<li><strong>Deterministic behavior by default.</strong> No hidden randomness, no wall-clock dependence inside core logic — the model can reason about outputs concretely.</li>
</ul>



<h2 class="wp-block-heading">Practical Takeaways</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Prefer</th><th>Over</th><th>Why</th></tr></thead><tbody><tr><td>Typed signatures</td><td>Untyped / duck-typed params</td><td>Constrains output shape</td></tr><tr><td>Sum types / enums</td><td>Magic integers or strings</td><td>Exhaustiveness enforced</td></tr><tr><td>Explicit imports</td><td>Global namespace</td><td>Clear dependency graph</td></tr><tr><td>Returned errors</td><td>Broad exception swallowing</td><td>Localized failure handling</td></tr><tr><td>Immutable data flow</td><td>Shared mutable state</td><td>Less aliasing to track</td></tr><tr><td>Standard library calls</td><td>Invented helpers</td><td>Matches training frequency</td></tr><tr><td>One canonical idiom</td><td>Five competing styles</td><td>Reduces variance in output</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>Rule of thumb:</strong> when choosing a language or refactoring a prompt for better one-shot results, pick the option that leaves the <em>fewest implicit decisions</em> to the model. Every explicit choice you encode in the language itself is a decision the model doesn&#8217;t have to guess.</p>



<h1 class="wp-block-heading">Language Competition</h1>



<p class="wp-block-paragraph">Comparing these languages: JavaScript, TypeScript, Lua, Go, Rust, C++, C, ObjC, Haskell, Elm, Python3, Perl, Perl6, PHP8, Vala, Java, Kotlin, Swift, C#, F#.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Language Feature</th><th>Languages that have it</th><th>Languages that lack it</th></tr></thead><tbody><tr><td>Typed signatures</td><td>TypeScript, Go, Rust, C++, C, ObjC, Haskell, Elm, Perl6, PHP8, Vala, Java, Kotlin, Swift, C#, F#</td><td>JavaScript, Lua, Python3, Perl</td></tr><tr><td>Sum types / enums</td><td>Go, Rust, Haskell, Elm, PHP8, Vala, Java, Kotlin, Swift, C#, F#</td><td>JavaScript, TypeScript, Lua, C++, C, ObjC, Python3, Perl, Perl6, C++</td></tr><tr><td>Optionality made explicit</td><td>Rust (<code>Option&lt;T&gt;</code>), Kotlin (<code>?</code>), Swift (<code>Optional</code>), TypeScript (strict null checks), Java (annotations)</td><td>JavaScript, Lua, C, C++, Python3, Perl, Perl6, PHP8, Go, ObjC</td></tr><tr><td>Uniform function call syntax</td><td>C, C++, Java, Kotlin, Swift, C#, F#, Go, Rust, Haskell, Elm, PHP8, Vala</td><td>JavaScript (optional chaining, spread, template literals), Perl (many sigils), Lua (mixed <code>:</code> and <code>.</code>)</td></tr><tr><td>No hidden mutation in syntax</td><td>Rust (ownership), Haskell (lazy purity), Elm (no side effects), Go (minimal), C (explicit)</td><td>JavaScript (proxies, getters/setters), C++ (operator overloading), Java (properties via beans), PHP8 (magic methods), Swift (computed properties), Kotlin (delegates)</td></tr><tr><td>Single obvious control-flow form</td><td>Go, Rust, C, C++, Java, C#, F#, Kotlin, Swift, Elm, Haskell</td><td>JavaScript (for-of, for-in, forEach, map/filter/reduce), Ruby-like sugar in PHP8, Perl (postfix if/unless)</td></tr><tr><td>Explicit imports</td><td>Go, Rust, ES modules (TS/JS), Java, C#, F#, Kotlin, Swift</td><td>C/C++ (#include is explicit but no module system), Perl (use), Python3 (implicit <strong>init</strong>), PHP8 (autoload), Lua (require), ObjC (@import)</td></tr><tr><td>Flat predictable module paths</td><td>Go, Rust, C, C++</td><td>Java (deep packages), C#/F# (namespaces), Kotlin (packages), Swift (modules + @objc), TS/JS (node_modules resolution)</td></tr><tr><td>Structured errors over exceptions</td><td>Go (error values), Rust (<code>Result&lt;T,E&gt;</code>), C (errno/return codes), Elm (typed Result)</td><td>Java (checked exceptions everywhere), C# (exceptions), Kotlin (exceptions), Swift (throws), C++ (exceptions optional), PHP8 (throw/catch), JS (try/catch only), Python3 (raise/except), Perl (die/warn), Perl6 (exception), ObjC (NSException)</td></tr><tr><td>One idiomatic recovery path</td><td>Rust (<code>?</code> operator), Go (bare error return), C (check errno)</td><td>Java (nested try/catch), C# (multiple catch filters), JS (no standard propagation), Python3 (broad except patterns)</td></tr><tr><td>Default immutability</td><td>Rust (borrow checker), Haskell (values immutable by default), Elm (immutable data)</td><td>JavaScript, TypeScript, Python3, Java, C#, C++, C, Go, PHP8, Perl, Perl6, Lua, Swift (var default), Kotlin (val default helps but var exists), Vala, ObjC</td></tr><tr><td>Pure-function-friendly design</td><td>Haskell, Elm, Rust (functional style encouraged), F#</td><td>C, C++, Java, C#, Objective-C, PHP8, Perl, Perl6, JavaScript, Python3 (mutable defaults common), Go, Kotlin, Swift, Vala, Lua</td></tr><tr><td>Consistent whitespace structure</td><td>Python3 (indentation-based), Go (gofmt enforces), Rust (rustfmt enforces), C (K&amp;R or LLVM style)</td><td>C++ (no enforced formatter), Java (no enforced formatter), C#/F# (formatter varies), Kotlin/Swift (flexible), JS/TS (prettier optional), PHP8 (PSR optional), Perl/Perl6 (freeform), Lua (freeform), ObjC (freeform)</td></tr><tr><td>Common delimiters &amp; punctuation</td><td>C, C++, Java, C#, F#, Kotlin, Swift, Go, Rust, PHP8, Vala</td><td>Python3 (whitespace-delimited, no braces/semicolons), Perl (sigils <code>$@%&amp;*</code>, flexible quoting), Lua (no semicolons, mixed <code>end</code> keywords), Haskell (layout rule, do notation), Elm (indentation-sensitive like Python)</td></tr><tr><td>Small independently callable units</td><td>Go, Rust, C, C++, Python3, Haskell, Elm, Java, C#, F#, Kotlin, Swift</td><td>Perl (monolithic scripts common), PHP8 (procedural legacy), Lua (small ecosystem), ObjC (framework-bound), C++ (template metaprogramming complexity)</td></tr><tr><td>Deterministic behavior by default</td><td>Rust, Haskell, Elm, Go, C, C++</td><td>JavaScript (event-loop timing, floating-point variance), Python3 (dict ordering pre-3.7, hash randomization), PHP8 (locale-dependent sorting), Perl (hash ordering), Java (HashMap iteration order), C# (dictionary enumeration), Kotlin (collection impl choices), Swift (Set unordered), Vala (GLib dict ordering)</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"></p><p>The post <a href="https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/">Language Characteristics that Help LLMs Write Better Code</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/28/language-characteristics-that-help-llms-write-better-code/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Learning Elm: fourth try with the LLM layout tests</title>
		<link>https://riceball.com/2026/09/14/learning-elm-fourth-try-with-the-llm-layout-tests/</link>
					<comments>https://riceball.com/2026/09/14/learning-elm-fourth-try-with-the-llm-layout-tests/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 15 Sep 2026 00:34:43 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30513</guid>

					<description><![CDATA[<p>Testing to see how the models do writing Elm code. Fourth try. I had Thaura read my AGENTS file, and critique it. I made the suggested changed, and also added more advice. Then, I started a fresh session and had it reorganize it. Here it is as a download (I had trouble pasting it here). [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/14/learning-elm-fourth-try-with-the-llm-layout-tests/">Learning Elm: fourth try with the LLM layout tests</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Testing to see how the models do writing Elm code. Fourth try.</p>



<p class="wp-block-paragraph">I had Thaura read my AGENTS file, and critique it. I made the suggested changed, and also added more advice. Then, I started a fresh session and had it reorganize it.</p>



<p class="wp-block-paragraph">Here it is as a download (I had trouble pasting it here).</p>



<div class="wp-block-file"><a id="wp-block-file--media-44012c76-921d-4afb-a4ab-f285e612bba7" href="https://riceball.com/wp-content/uploads/sites/2/2026/09/AGENTS.md_.txt">AGENTS.md</a><a href="https://riceball.com/wp-content/uploads/sites/2/2026/09/AGENTS.md_.txt" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-44012c76-921d-4afb-a4ab-f285e612bba7">Download</a></div>



<h2 class="wp-block-heading">Scoreboard</h2>



<p class="wp-block-paragraph">I used the Free versions in OpenCode, which has some free models included.</p>



<p class="wp-block-paragraph">Token counts are approximate.</p>



<figure class="wp-block-table"><table><thead><tr><th>LLM</th><th>Tokens</th><th>Works?</th><th>Notes</th></tr></thead><tbody><tr><td>Thaura (Qwen3.8)</td><td></td><td>Y</td><td>Had very few bugs, and they were corrected quickly.</td></tr><tr><td>Ling3.0</td><td>34K</td><td>Y</td><td>Layout is a little off. Right column under left.</td></tr><tr><td>MiMo2.5</td><td>26K</td><td>Y</td><td>Built it quickly, and the layout is correct.</td></tr><tr><td>MuseSpark1.2</td><td>35K</td><td>Y</td><td>Built it quickly, and the layout is correct.</td></tr><tr><td>MuseSpark1.3</td><td>31K</td><td>Y</td><td>Built it quickly, and the layout is correct.</td></tr><tr><td>Nemotron3</td><td>35K</td><td>Y</td><td>Took so long I could not monitor it.</td></tr><tr><td>Nemotron3.5</td><td></td><td>N</td><td>** See notes</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">For this round, I used an AGENTS.md file that was improved by asking Thaura to critique it. The critique was based on what happened during the LLMs coding and testing. I made changes, and then asked Thaura to organize it.</p>



<p class="wp-block-paragraph">I figured this would help Thaura, which was already succeeding at writing the code. It breezed through the task, and appeared to use only a small amount of energy (Thaura converts tokens into energy usage, and said it was like driving under 500 meters).</p>



<p class="wp-block-paragraph">It also seems to have helped the others as well.</p>



<p class="wp-block-paragraph">For each build, I asked the agent to critique AGENTS.md, and write the critique to critique.md. Mimo failed to do that, but Ling and Muse Spark did it. So they can compare how their build went, and how the AGENTS.md file helped.</p>



<p class="wp-block-paragraph">One thing that jumped out was that the LLMs asked for a more determinate test, with more specific layout details. They asked me to be more specific about what I wanted.</p>



<h2 class="wp-block-heading">Nemotron 3.5</h2>



<p class="wp-block-paragraph">Again, Nemotron had problems.</p>



<p class="wp-block-paragraph">I told it to read AGENTS.md, and got this:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript shcb-wrap-lines">Theytics motherellsellsamu inells <span class="hljs-keyword">this</span> alongellsells <span class="hljs-keyword">from</span> indigenousellsells Carn shred mill certifiedells
</code></span></pre>


<p class="wp-block-paragraph">It&#8217;s not having a good day.</p>



<p class="wp-block-paragraph">Eventually, I interrupted it, and the layout was there, but the CSS wasn&#8217;t, and the Playwright tests weren&#8217;t done. So I gave it the &#8220;OK&#8221; to complete that. It still didn&#8217;t end up working.</p>



<p class="wp-block-paragraph">Then it said:</p>


<pre class="wp-block-code"><span><code class="hljs shcb-wrap-lines">It seems port 800 الخارجية-orientedे- extern需-exل-allow-its owners المشاكل mu로서 cơis(),
 lui. ث.
 starken-ise anno (h. (something
 also . ( weiteren
 شركة томnil
</code></span></pre>


<h2 class="wp-block-heading">Performance Improvements</h2>



<figure class="wp-block-table"><table><thead><tr><th>LLM</th><th>Tokens<br>layout1</th><th>Tokens<br>layout2</th><th>Tokens<br>layout3</th><th>Tokens<br>layout4</th><th>Effect on token use</th></tr></thead><tbody><tr><td>Thaura (Qwen3.8)</td><td></td><td></td><td></td><td></td><td>suspect a reduction</td></tr><tr><td>Ling3.0</td><td>51K</td><td>42K + 26K</td><td>42K</td><td>34K</td><td>general reduction</td></tr><tr><td>MiMo2.5</td><td>19K</td><td>20K</td><td>37K</td><td>26K</td><td>general increase, but improves from 3 to 4</td></tr><tr><td>MuseSpark1.2</td><td>20K</td><td>42K</td><td>43K</td><td>35K</td><td>general increase, but improves from 3 to 4</td></tr><tr><td>MuseSpark1.3</td><td>16K</td><td>21K</td><td>27K</td><td>31K</td><td>increase</td></tr><tr><td>Nemotron3</td><td>24K</td><td>29K</td><td>34K</td><td>35K</td><td>increase</td></tr><tr><td>Nemotron3.5</td><td></td><td></td><td></td><td></td><td>oh well</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Ignore the layout1 counts: some of these runs didn&#8217;t succeed. So those values aren&#8217;t all valid.</p>



<p class="wp-block-paragraph">The layout2 counts are more valid, because they all produced a reasonable result, excepting Nemotron3.5.</p>



<p class="wp-block-paragraph">The change from version 3 to version 4 of AGENTS.md was generally saving tokens across three (or four) of the 7 models. AGENTS.md 4 was much longer, and more comprehensive, so it consumed more context, but it prevented the models from making so many errors, and requiring more compile-debug cycles, saving both time and tokens.</p>



<p class="wp-block-paragraph">Because I can&#8217;t see token counts on Thaura, I cannot be certain the count went down, but I know that the &#8220;miles driven&#8221; metric it provides in its stead plummeted, and it produced the code quickly, and it didn&#8217;t appear to be running the compiler as much. This wasn&#8217;t a surprise, because I asked Thaura to help me improve my AGENTS.md, and it listed all the ways it tripped up, and told me how it could have avoided the bugs.</p>



<p class="wp-block-paragraph">We see some large drops in token counts, approximately 10k or 25% less for three models.</p>



<p class="wp-block-paragraph">However, it&#8217;s obvious that my AGENTS.md is not cross-platform. A lot of it reads like a &#8220;guide to pitfalls and landmines&#8221; across a space that&#8217;s rough and rocky. It works for Thaura&#8217;s LLM to make this specific project, but it could also be a hindrance to a different project.</p>



<h2 class="wp-block-heading">AGENTS.md Effectiveness</h2>



<p class="wp-block-paragraph"><a href="https://www.infoq.com/news/2026/03/agents-context-file-value-review/" target="_blank" rel="noopener">New Research Reassesses the Value of AGENTS.md Files for AI Coding</a> reported that AGENTS.md, across 60,000 instances found on GitHub, seemed to produce a 4% improvement, and in some cases, made things worse.</p>



<p class="wp-block-paragraph">My sense is that a detailed spec in AGENTS.md with advice about how to program initially costs more tokens, but as these are improved, performance will improve.</p>



<h2 class="wp-block-heading">Code Quality</h2>



<p class="wp-block-paragraph">I can&#8217;t evaluate it because I don&#8217;t know Elm well enough &#8211; however, this process of discussing the problem code with LLMs has helped my learning considerably.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">All the models basically completed the code without asking questions, but, once again, Nemotrion 3.5 Lighting Free failed.</p>



<p class="wp-block-paragraph">Here is a ZIP file with all the generated code, and project files.</p>



<div class="wp-block-file"><a id="wp-block-file--media-e099e975-59fd-4b3b-9fb8-67e293b68bbc" href="https://riceball.com/wp-content/uploads/sites/2/2026/09/layout4.zip">layout4</a><a href="https://riceball.com/wp-content/uploads/sites/2/2026/09/layout4.zip" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-e099e975-59fd-4b3b-9fb8-67e293b68bbc">Download</a></div><p>The post <a href="https://riceball.com/2026/09/14/learning-elm-fourth-try-with-the-llm-layout-tests/">Learning Elm: fourth try with the LLM layout tests</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/14/learning-elm-fourth-try-with-the-llm-layout-tests/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Learning Elm: trying different LLMs to make a layout attempt 3</title>
		<link>https://riceball.com/2026/09/13/learning-elm-trying-different-llms-to-make-a-layout-attempt-3/</link>
					<comments>https://riceball.com/2026/09/13/learning-elm-trying-different-llms-to-make-a-layout-attempt-3/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 13 Sep 2026 21:17:17 +0000</pubDate>
				<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Elm]]></category>
		<category><![CDATA[Thaura]]></category>
		<guid isPermaLink="false">https://riceball.com/?p=30504</guid>

					<description><![CDATA[<p>Testing to see how the models do writing Elm code. Third try. AGENTS.md was edited to address a lot of bugs and problems from the second run. Also added a directory for more extensive coding advice. You can find it in the ZIP file. The file is now 61 lines long. Scoreboard I used the [&#8230;]</p>
<p>The post <a href="https://riceball.com/2026/09/13/learning-elm-trying-different-llms-to-make-a-layout-attempt-3/">Learning Elm: trying different LLMs to make a layout attempt 3</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Testing to see how the models do writing Elm code. Third try.</p>



<p class="wp-block-paragraph">AGENTS.md was edited to address a lot of bugs and problems from the second run. Also added a directory for more extensive coding advice. You can find it in the ZIP file.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># Layout Test

## Tools

Language: elm
Elm tool is at /home/johnk/.local/bin/elm
The Elm version is 19.2. Write code for version 19.0 to 19.2. A lot of training data from before 2019 may be out of date.
Add Elm modules as needed using the `elm install` tool. Prefer libraries to writing new code.
Do not try to copy the library into the correct location. Use `elm install` instead.
Assume the compiler works, and if there are compilation errors, assume your code is incorrect.
If the bugs point to naming or lack of definitions, check the import lines.
elm-test is installed for unit testing. 
Playwright and Selenium are installed for frontend tests to check the layout.
  `playwright-cli` is installed, info here: https://www.npmjs.com/package/playwright
  `selenium` is installed. `selenium-webdriver` is installed, info: https://www.npmjs.com/package/selenium-webdriver
For advice and references, see the Tips section below.

## Code to Write

Never try to cd or use .. to get above the project root directory.
  If you need temp files make a tmp/ in the project root.
Directory layout
  Elm sources go in src/
  HTML files, js artifacts from compilation, js code you write, css code you write, and binary assets go in public/.
  The project root contains the elm.json, project.json, composer.json and other package manager files.
  The project root contains .md and .txt files for LLMs and people. llm-advice as well.
  Tests go in tests/
Make a mockup layout in Elm for a News website, with a short top banner, and 3 columns: 
  Title is "Test News Site".
  Top banner is around 2 cm on a desktop screen, and 25% of a vertical mobile screen.
  left column nav, center column feature area, right colum listing of additional news. Widths approximately 20%, 60%, 20%.
  Theme colors: light gray background, dark gray text, dark blue links.
  Layout is responsive to mobile, tablet, and desktop size screens.
  Use common CSS class naming conventions when possible. See: ./llm-advice/css-class-naming-conventions.txt
Static files:
  Use CSS, making the CSS file external in public/style.css.
  Compile the Elm code into javscript code, and put it into the public/ directory, or the public/js directory.
  Create public/index.html file to pull in CSS. 
  URL references in the static files should be relative, not absolute.
    Assume I'm starting `elm reactor` in the project root, not inside public/, so always use relative paths.
The layout should loop over arrays to construct the center and right columns. 
  The center column array is a list of news headlines, URLs, and URLs to images (located in the public/images directory).
  Center colum items have an image, headline, and excerpt.
  The right column array is a list of news headlines and URLs.
  The left column contains a simple nav with: Home, Local News, Breaking News.
Testing
  At the very minimum, create a Playwright test to check that the browser can display the layout.
  Often, code compiles and works, but the index.html file has bad URLs that won't load the artifacts.
    Problems include: /main.js - absolute path doesn't work; ../dist/main.js - the http server doesn't allow going up a directory.
    Solution is to use relative paths, and generate artifacts in public/, and then use url: main.js
    Same has happened with CSS files.

## Tips

The following advice below may help avoid getting into endless debugging loops.
Important: the assumption that the tools and compilers are not working often leads to looping over tests that keep failing. This is because you are falling into the compiler developers test code. Assume that the elm compiler is correct. If it keeps failing, stop and tell the user.
Read about shadowing: ./llm-advice/shadowing.txt
Current calling convention in index.html is Elm.Main.init({ node: document.getElementById('the-node-id') })
elm-test Refs: https://elmprogramming.com/easy-to-test.html https://github.com/elm-explorations/test
For advice about v19, see: https://raw.githubusercontent.com/elm/compiler/refs/heads/main/docs/upgrade-instructions/0.19.0.md
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"># Layout Test</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">## Tools</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">Language: elm</span></span>
<span class="line"><span style="color: #D4D4D4">Elm tool is at /home/johnk/.local/bin/elm</span></span>
<span class="line"><span style="color: #D4D4D4">The Elm version is 19.2. Write code for version 19.0 to 19.2. A lot of training data from before 2019 may be out of date.</span></span>
<span class="line"><span style="color: #D4D4D4">Add Elm modules as needed using the `elm install` tool. Prefer libraries to writing new code.</span></span>
<span class="line"><span style="color: #D4D4D4">Do not try to copy the library into the correct location. Use `elm install` instead.</span></span>
<span class="line"><span style="color: #D4D4D4">Assume the compiler works, and if there are compilation errors, assume your code is incorrect.</span></span>
<span class="line"><span style="color: #D4D4D4">If the bugs point to naming or lack of definitions, check the import lines.</span></span>
<span class="line"><span style="color: #D4D4D4">elm-test is installed for unit testing. </span></span>
<span class="line"><span style="color: #D4D4D4">Playwright and Selenium are installed for frontend tests to check the layout.</span></span>
<span class="line"><span style="color: #D4D4D4">  `playwright-cli` is installed, info here: https://www.npmjs.com/package/playwright</span></span>
<span class="line"><span style="color: #D4D4D4">  `selenium` is installed. `selenium-webdriver` is installed, info: https://www.npmjs.com/package/selenium-webdriver</span></span>
<span class="line"><span style="color: #D4D4D4">For advice and references, see the Tips section below.</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">## Code to Write</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">Never try to cd or use .. to get above the project root directory.</span></span>
<span class="line"><span style="color: #D4D4D4">  If you need temp files make a tmp/ in the project root.</span></span>
<span class="line"><span style="color: #D4D4D4">Directory layout</span></span>
<span class="line"><span style="color: #D4D4D4">  Elm sources go in src/</span></span>
<span class="line"><span style="color: #D4D4D4">  HTML files, js artifacts from compilation, js code you write, css code you write, and binary assets go in public/.</span></span>
<span class="line"><span style="color: #D4D4D4">  The project root contains the elm.json, project.json, composer.json and other package manager files.</span></span>
<span class="line"><span style="color: #D4D4D4">  The project root contains .md and .txt files for LLMs and people. llm-advice as well.</span></span>
<span class="line"><span style="color: #D4D4D4">  Tests go in tests/</span></span>
<span class="line"><span style="color: #D4D4D4">Make a mockup layout in Elm for a News website, with a short top banner, and 3 columns: </span></span>
<span class="line"><span style="color: #D4D4D4">  Title is &quot;Test News Site&quot;.</span></span>
<span class="line"><span style="color: #D4D4D4">  Top banner is around 2 cm on a desktop screen, and 25% of a vertical mobile screen.</span></span>
<span class="line"><span style="color: #D4D4D4">  left column nav, center column feature area, right colum listing of additional news. Widths approximately 20%, 60%, 20%.</span></span>
<span class="line"><span style="color: #D4D4D4">  Theme colors: light gray background, dark gray text, dark blue links.</span></span>
<span class="line"><span style="color: #D4D4D4">  Layout is responsive to mobile, tablet, and desktop size screens.</span></span>
<span class="line"><span style="color: #D4D4D4">  Use common CSS class naming conventions when possible. See: ./llm-advice/css-class-naming-conventions.txt</span></span>
<span class="line"><span style="color: #D4D4D4">Static files:</span></span>
<span class="line"><span style="color: #D4D4D4">  Use CSS, making the CSS file external in public/style.css.</span></span>
<span class="line"><span style="color: #D4D4D4">  Compile the Elm code into javscript code, and put it into the public/ directory, or the public/js directory.</span></span>
<span class="line"><span style="color: #D4D4D4">  Create public/index.html file to pull in CSS. </span></span>
<span class="line"><span style="color: #D4D4D4">  URL references in the static files should be relative, not absolute.</span></span>
<span class="line"><span style="color: #D4D4D4">    Assume I&#39;m starting `elm reactor` in the project root, not inside public/, so always use relative paths.</span></span>
<span class="line"><span style="color: #D4D4D4">The layout should loop over arrays to construct the center and right columns. </span></span>
<span class="line"><span style="color: #D4D4D4">  The center column array is a list of news headlines, URLs, and URLs to images (located in the public/images directory).</span></span>
<span class="line"><span style="color: #D4D4D4">  Center colum items have an image, headline, and excerpt.</span></span>
<span class="line"><span style="color: #D4D4D4">  The right column array is a list of news headlines and URLs.</span></span>
<span class="line"><span style="color: #D4D4D4">  The left column contains a simple nav with: Home, Local News, Breaking News.</span></span>
<span class="line"><span style="color: #D4D4D4">Testing</span></span>
<span class="line"><span style="color: #D4D4D4">  At the very minimum, create a Playwright test to check that the browser can display the layout.</span></span>
<span class="line"><span style="color: #D4D4D4">  Often, code compiles and works, but the index.html file has bad URLs that won&#39;t load the artifacts.</span></span>
<span class="line"><span style="color: #D4D4D4">    Problems include: /main.js - absolute path doesn&#39;t work; ../dist/main.js - the http server doesn&#39;t allow going up a directory.</span></span>
<span class="line"><span style="color: #D4D4D4">    Solution is to use relative paths, and generate artifacts in public/, and then use url: main.js</span></span>
<span class="line"><span style="color: #D4D4D4">    Same has happened with CSS files.</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">## Tips</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">The following advice below may help avoid getting into endless debugging loops.</span></span>
<span class="line"><span style="color: #D4D4D4">Important: the assumption that the tools and compilers are not working often leads to looping over tests that keep failing. This is because you are falling into the compiler developers test code. Assume that the elm compiler is correct. If it keeps failing, stop and tell the user.</span></span>
<span class="line"><span style="color: #D4D4D4">Read about shadowing: ./llm-advice/shadowing.txt</span></span>
<span class="line"><span style="color: #D4D4D4">Current calling convention in index.html is Elm.Main.init({ node: document.getElementById(&#39;the-node-id&#39;) })</span></span>
<span class="line"><span style="color: #D4D4D4">elm-test Refs: https://elmprogramming.com/easy-to-test.html https://github.com/elm-explorations/test</span></span>
<span class="line"><span style="color: #D4D4D4">For advice about v19, see: https://raw.githubusercontent.com/elm/compiler/refs/heads/main/docs/upgrade-instructions/0.19.0.md</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The file is now 61 lines long.</p>



<h2 class="wp-block-heading">Scoreboard</h2>



<p class="wp-block-paragraph">I used the Free versions in OpenCode.</p>



<p class="wp-block-paragraph">The number scores are about how good the layout looks. The first one is scored 5, and subsequent scores are based on how good it looks relative to the first one.</p>



<p class="wp-block-paragraph">I am not going to try and evaluate the &#8220;look&#8221; anymore. All the layouts are basically midrange in quality, and all will require work to look nice. Additionally, it&#8217;s not like I&#8217;ve provided an image of the desired layout, so it seems pointless to compare.</p>



<p class="wp-block-paragraph">Token counts are approximate.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>LLM</th><th>Tokens</th><th>Works?</th><th>Notes</th></tr></thead><tbody><tr><td>Thaura (<a href="https://openlm.ai/qwen3.8/">Qwen3.8</a>)</td><td></td><td>Y</td><td>Basic. Not chatty!</td></tr><tr><td><a href="https://developer.ant-ling.com/en/docs/models/ling/">Ling3.0</a></td><td>42K</td><td>Y</td><td>Had lots of connection errors, but it still produced everything.</td></tr><tr><td><a href="https://mimo.xiaomi.com/mimo-v2-5">MiMo2.5</a></td><td>37K</td><td>YN</td><td>Declared a &#8220;port&#8221; module erroneously. Layout is broken, with right column below left and center. Not tragic.</td></tr><tr><td><a href="https://developer.meta.com/ai/models/muse-spark-1-2/">MuseSpark1.2</a></td><td>43K</td><td>Y</td><td>It just produced it. Seemed to spend time writing test cases.</td></tr><tr><td><a href="https://developer.meta.com/ai/models/muse-spark/">MuseSpark1.3</a></td><td>27K</td><td>Y</td><td>It made 14 tests.</td></tr><tr><td><a href="https://research.nvidia.com/labs/nemotron/Nemotron-3/">Nemotron3</a></td><td>34K</td><td>Y</td><td>Interaction with the model was slow. Seemed to take 90 minutes. I stopped paying attention.</td></tr><tr><td><a href="https://docs.nvidia.com/nim/large-language-models/2.0.10/get-started/advanced/get-started-nemotron-3.5-lightning.html">Nemotron3.5</a></td><td></td><td>N</td><td>** See notes</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">The commands I used:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-tag">read</span> <span class="hljs-selector-tag">AGENTS</span><span class="hljs-selector-class">.md</span>
<span class="hljs-selector-tag">build</span> <span class="hljs-selector-tag">it</span> <span class="hljs-selector-tag">--</span> <span class="hljs-selector-tag">sometimes</span></code></span></pre>


<p class="wp-block-paragraph">I expected token counts to rise as the prompts grew, but that didn&#8217;t seem to happen in any appreciable way. Sometimes, the token count decreased. This may be related to my manually setting up and installing as many tools as I thought it&#8217;d need. It may be related to specifying things like filenames and locations explicitly.</p>



<p class="wp-block-paragraph">I told it I would use <code>elm reactor</code> from the project root to view the site, but it seemed like the LLMs preferred to use the http server in Python, and ran it from public/. This could cause it to pass tests that would fail, due to bad paths, if the server ran in the project root.</p>



<p class="wp-block-paragraph">Adding the requirement to produce a Playwright test helped tremendously.</p>



<h2 class="wp-block-heading">Time Spent</h2>



<p class="wp-block-paragraph">I didn&#8217;t keep good track, but until this round, it was around 2-3 hours per to test and produce each of the last three reports, including changes to the prompt in AGENTS.md, building the projects, and posting it to the site.</p>



<p class="wp-block-paragraph">As the prompt got longer, the build times grew to several minutes, and sometimes it felt like 30 minutes or more.</p>



<p class="wp-block-paragraph">This round, Nemotron 3 took over 90 minutes.</p>



<h2 class="wp-block-heading">Nemotron 3.5 Lighting Free</h2>



<p class="wp-block-paragraph">At 13K tokens, it crashed out:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript shcb-wrap-lines">Let <span class="hljs-string">"action: layout main: 56.tabular: "</span>Ginger Analytics summary full não complete complete deployingتهاء kompletFull完成 الكامل midline—:  clauses <span class="hljs-number">3</span>:<span class="hljs-comment">//umé 1 layouts widths, I, kh</span>
</code></span></pre>


<p class="wp-block-paragraph">Just for giggles, I told it <code>continue</code>. It just spun the spinner several minutes before I quit and restarted.</p>



<p class="wp-block-paragraph">The second time around, it wanted access to /tmp, and I refused it. Then it got into a death spiral at 45K when it couldn&#8217;t figure out how to end a record that starts with &#8216;{&#8216; and that contained a literal list, which looks like [ &#8230; ], with a matching &#8216;}&#8217;.</p>



<h2 class="wp-block-heading">Code Quality</h2>



<p class="wp-block-paragraph">I can&#8217;t evaluate it because I don&#8217;t know Elm well enough &#8211; however, this process of discussing the problem code with LLMs has helped my learning considerably.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">All the models basically completed the code without asking questions, but, once again, Nemotrion 3.5 Lighting Free failed.</p><p>The post <a href="https://riceball.com/2026/09/13/learning-elm-trying-different-llms-to-make-a-layout-attempt-3/">Learning Elm: trying different LLMs to make a layout attempt 3</a> first appeared on <a href="https://riceball.com">🍙</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://riceball.com/2026/09/13/learning-elm-trying-different-llms-to-make-a-layout-attempt-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
