<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: faliye</title>
    <description>The latest articles on DEV Community by faliye (@faliye).</description>
    <link>https://dev.to/faliye</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg</url>
      <title>DEV Community: faliye</title>
      <link>https://dev.to/faliye</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/faliye"/>
    <language>en</language>
    <item>
      <title>Benchmarking 6 Open LLMs on a 2-Machine RPC Cluster (Consumer GPUs, ~96GB VRAM)</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Thu, 22 Oct 2026 13:27:11 +0000</pubDate>
      <link>https://dev.to/faliye/benchmarking-6-open-llms-on-a-2-machine-rpc-cluster-consumer-gpus-96gb-vram-j2p</link>
      <guid>https://dev.to/faliye/benchmarking-6-open-llms-on-a-2-machine-rpc-cluster-consumer-gpus-96gb-vram-j2p</guid>
      <description>&lt;p&gt;In the endless pursuit of "bigger, bigger, and even bigger," I finally reached this point: two machines directly connected via a local area network, using RPC scheduling to split and load the model layer by layer across both hosts.&lt;/p&gt;

&lt;p&gt;The reason is simple—&lt;strong&gt;I have a limited budget&lt;/strong&gt;. Buying a professional-grade graphics card with 96GB of VRAM would definitely not pass my wife's approval. So for consumer-level GPU users on a budget like me, linking multiple machines and GPUs via RPC is currently the only realistic option.&lt;/p&gt;

&lt;p&gt;The setup itself is straightforward: connect two machines with an Ethernet cable. I used a nominally 5Gbps CAT6A cable, and the actual tested bandwidth is about 4.7Gbps—yielding a throughput of around 500 MB/s. Under this bandwidth, &lt;strong&gt;llama.cpp's RPC chain invocation is currently the only viable choice&lt;/strong&gt; (a Thunderbolt 5 adapter is on the way; once it arrives, it should close some of the performance gap).&lt;/p&gt;

&lt;p&gt;The ambient temperature during testing was 35°C; the CPU reached 76°C, and the RTX 5090 (power-limited to 450W) peaked at 68°C.&lt;/p&gt;

&lt;p&gt;No special optimizations were made at the architecture level—I just got the official RPC server running end-to-end first, leaving optimizations for later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardware Setup
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Host&lt;/th&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;th&gt;VRAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host 1&lt;/td&gt;
&lt;td&gt;RTX 5080&lt;/td&gt;
&lt;td&gt;16GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Host 1&lt;/td&gt;
&lt;td&gt;RTX 5060 Ti ×2&lt;/td&gt;
&lt;td&gt;16GB × 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Host 2&lt;/td&gt;
&lt;td&gt;RTX 5090&lt;/td&gt;
&lt;td&gt;32GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Host 2&lt;/td&gt;
&lt;td&gt;RTX 5060 Ti&lt;/td&gt;
&lt;td&gt;16GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This totals approximately 96GB of VRAM, with the two hosts directly connected via a CAT6A network cable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pitfall Record: tensor-split Order
&lt;/h2&gt;

&lt;p&gt;Once the two machines were connected, it was time to pick the models. With a 96GB budget, there isn't actually much room for choice—you have to consider production-level concurrency requirements (according to current market expectations, a 96GB setup is considered a poor investment if it can't support a team of 8-15 people), while also balancing KV context size and model precision.&lt;/p&gt;

&lt;p&gt;When running the first model (Qwen3.6-35B-A3B Q8_0), I noticed the main card (5090) was using less than 7GB of VRAM—a massive waste. At the time, &lt;code&gt;--tensor-split&lt;/code&gt; was set to &lt;code&gt;32,16,16,16,16&lt;/code&gt;, intending to allocate the largest share to the main card. But the actual device order was:&lt;br&gt;
&lt;code&gt;[ local - RPC : 5080 , local - RPC : 5060Ti , local - RPC : 5060Ti , 5090 , 5060Ti ]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In other words, &lt;strong&gt;the remote RPC cards were placed at the front, while the local main card was at the end&lt;/strong&gt;—the exact opposite of what I expected. This is why the VRAM allocation didn't land on the 5090 as intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Candidate Models
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Quantization&lt;/th&gt;
&lt;th&gt;Type / Active Params&lt;/th&gt;
&lt;th&gt;Layers&lt;/th&gt;
&lt;th&gt;Model Size&lt;/th&gt;
&lt;th&gt;Thinking Mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;qwen36 · Qwen3.6-35B-A3B&lt;/td&gt;
&lt;td&gt;Q8_0&lt;/td&gt;
&lt;td&gt;MoE, 3B active&lt;/td&gt;
&lt;td&gt;Split into 5 layers&lt;/td&gt;
&lt;td&gt;~42GB&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;llama33 · Llama-3.3-70B&lt;/td&gt;
&lt;td&gt;Q6_K&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;80 layers, split into 5 parts&lt;/td&gt;
&lt;td&gt;~73GB&lt;/td&gt;
&lt;td&gt;No thinking capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen25 · Qwen2.5-72B&lt;/td&gt;
&lt;td&gt;Q6_K&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;80 layers&lt;/td&gt;
&lt;td&gt;~80GB&lt;/td&gt;
&lt;td&gt;No thinking capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;glm · GLM-4.5-Air&lt;/td&gt;
&lt;td&gt;Q4_K_M&lt;/td&gt;
&lt;td&gt;MoE&lt;/td&gt;
&lt;td&gt;46 layers&lt;/td&gt;
&lt;td&gt;~73GB&lt;/td&gt;
&lt;td&gt;No thinking capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen235 · Qwen3-235B-A22B-2507&lt;/td&gt;
&lt;td&gt;Q2_K_XL&lt;/td&gt;
&lt;td&gt;MoE&lt;/td&gt;
&lt;td&gt;94 layers&lt;/td&gt;
&lt;td&gt;~88GB&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-120b&lt;/td&gt;
&lt;td&gt;MXFP4&lt;/td&gt;
&lt;td&gt;MoE&lt;/td&gt;
&lt;td&gt;36 layers&lt;/td&gt;
&lt;td&gt;~65GB&lt;/td&gt;
&lt;td&gt;Cannot disable, set to "low"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The comparison between Qwen3.6-35B-A3B and Llama-3.3-70B perfectly illustrates the architectural differences.&lt;/em&gt; Llama is a Dense model—every token activates all 80 layers of parameters, so the overhead introduced by splitting across 5 GPUs plus one cross-machine network hop is magnified by about 9 times. In practice, its speed is only about 10 tok/s—barely enough for one person doing translation work (close to reading speed), but with noticeable latency. On the other hand, Qwen3.6 is an MoE model, activating only 3B parameters per token; the computation involved in running it on the same 5 GPUs is significantly lower.&lt;/p&gt;

&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;p&gt;With thinking mode disabled, the models were evaluated across 5 dimensions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Measurement Content&lt;/th&gt;
&lt;th&gt;Test Cases&lt;/th&gt;
&lt;th&gt;Scoring Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Speed / Concurrency&lt;/td&gt;
&lt;td&gt;TTFT (Time to First Token), Decode TPS, Performance degradation at 1/2/4 concurrency&lt;/td&gt;
&lt;td&gt;Automated load test&lt;/td&gt;
&lt;td&gt;Fully automated (tok/s, TTFT ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Translation Error Rate&lt;/td&gt;
&lt;td&gt;Rare/error-prone characters (from real novel corpora), JP to ZH, including classic mistranslation traps&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;Fully automated (compared vs standard translation → error rate)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Code Understanding&lt;/td&gt;
&lt;td&gt;High difficulty: Bug troubleshooting, behavior prediction, hierarchical allocator implementation, TP bandwidth reasoning, bash traps, refactoring&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Manual scoring (based on checkpoints)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Hallucination Rate&lt;/td&gt;
&lt;td&gt;False premises, fake citations, fabricated terms/APIs, unknowable questions, translation traps—all fact-checked&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;Heuristic + manual judgment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Translation Proofreading/Correction&lt;/td&gt;
&lt;td&gt;Proofreading and correction, polishing fidelity, terminology consistency&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Scored separately from scratch translation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The judge was primarily Claude 3.5 Sonnet (Opus 4.8 equivalent internally), supplemented by partial manual review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A few notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I could only run models my hardware could handle; models under 48GB were tested in previous articles.&lt;/li&gt;
&lt;li&gt;This is a personal test, and the test case design inherently carries some subjectivity.&lt;/li&gt;
&lt;li&gt;All tests were single runs, with no voting mechanisms or self-reflection—accuracy relied entirely on the model's own restraint. If popular multi-path reasoning verification were applied, accuracy would likely improve, but this requires more compute and time, so it wasn't done here.&lt;/li&gt;
&lt;li&gt;The sample sizes in dimensions 3, 4, and 5 are very small (6/24/9 questions respectively). Any disputed judgment is enough to change the rankings. Please view the "Overall Comparison" conclusions below as a directional signal rather than a statistically significant difference.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  VRAM Usage per Model (Initial Test Run)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Host 1 (5080 + 5060Ti×2)&lt;/th&gt;
&lt;th&gt;Host 2 (5090 + 5060Ti)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.6-35B-A3B Q8_0&lt;/td&gt;
&lt;td&gt;13.0GB / 14.0GB / 8.3GB&lt;/td&gt;
&lt;td&gt;6.9GB / 7.9GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama-3.3-70B Q6_K&lt;/td&gt;
&lt;td&gt;12.4GB / 11.1GB / 13.8GB&lt;/td&gt;
&lt;td&gt;22.7GB (13%) / 13.7GB (23%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen2.5-72B Q6_K&lt;/td&gt;
&lt;td&gt;13.4GB / — / —&lt;/td&gt;
&lt;td&gt;24.7GB / 14.8GB / 12.0GB (100%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GLM-4.5-Air Q4_K_M&lt;/td&gt;
&lt;td&gt;11.2GB / 10.1GB (100%) / 10.1GB&lt;/td&gt;
&lt;td&gt;28.0GB / 8.7GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3-235B-A22B-2507 Q2_K_XL&lt;/td&gt;
&lt;td&gt;14.8GB / 14.8GB / 14.2GB&lt;/td&gt;
&lt;td&gt;28.8GB / 13.4GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss-120b MXFP4&lt;/td&gt;
&lt;td&gt;11.0GB / 11.3GB (57%) / 9.1GB&lt;/td&gt;
&lt;td&gt;26.8GB / 8.0GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note: In-host GPU ordering and VRAM allocation ratios are heavily influenced by &lt;code&gt;--tensor-split&lt;/code&gt; and loading sequence; host/card allocation is not fixed across models—it reflects the actual RPC scheduling results in a specific run.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overall Comparison Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model (Quant)&lt;/th&gt;
&lt;th&gt;Type / Active&lt;/th&gt;
&lt;th&gt;Decode tok/s (short ctx)&lt;/th&gt;
&lt;th&gt;Max Usable Context&lt;/th&gt;
&lt;th&gt;Error Rate ↓&lt;/th&gt;
&lt;th&gt;Code Understanding&lt;/th&gt;
&lt;th&gt;Hallucination Rate ↓&lt;/th&gt;
&lt;th&gt;Proofreading&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qwen3.6-35B-A3B Q8_0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MoE 3B&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;35.6%&lt;/td&gt;
&lt;td&gt;83%&lt;/td&gt;
&lt;td&gt;18.8%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;gpt-oss-120b MXFP4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MoE 5.1B&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;45.5%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;56.3% ❌&lt;/td&gt;
&lt;td&gt;83.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GLM-4.5-Air Q4_K_M&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MoE 12B&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;65K&lt;/td&gt;
&lt;td&gt;40.6%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;70.8% ❌&lt;/td&gt;
&lt;td&gt;94%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qwen3-235B-A22B-2507 Q2_K_XL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MoE 22B&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;8K ❌&lt;/td&gt;
&lt;td&gt;35.6%&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;35.4%&lt;/td&gt;
&lt;td&gt;89%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qwen2.5-72B Q6_K&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;42.6%&lt;/td&gt;
&lt;td&gt;83%&lt;/td&gt;
&lt;td&gt;54.2%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Llama-3.3-70B Q6_K&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;98K&lt;/td&gt;
&lt;td&gt;54.5% ❌&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;75.0% ❌&lt;/td&gt;
&lt;td&gt;78%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Note: "Max Usable Context" reflects the measured upper limit under the specific resource allocation, not the model's inherent capability limit.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Conclusion&lt;/strong&gt;: In a CAT6A (5Gbps) network and llama.cpp RPC chain invocation environment, &lt;strong&gt;Qwen3.6-35B-A3B Q8_0 is the best-performing model overall in this test&lt;/strong&gt;—it ranks at the top in speed, concurrency degradation, translation error rate, and hallucination suppression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;After finishing the Qwen2.5 run, I looked back at the VRAM usage and realized that the SAM/CLIP small models left over from earlier tests hadn't actually been completely offloaded. This is a good reminder: in an environment running multiple models mixed together, you should always manually verify the VRAM that "should be freed," rather than blindly trusting that a process exit will definitely clean it up.&lt;/p&gt;

&lt;p&gt;Another thought worth recording: &lt;strong&gt;Qwen3.6-35B-A3B Q8_0 only took up about 42GB of VRAM, which means it could actually run entirely on a single machine.&lt;/strong&gt; This left me in deep thought—I went through all this trouble to build a dual-node RPC cluster, only to end up essentially running a model that a single machine could handle? I'll continue pondering this question when the Thunderbolt 5 adapters arrive for the next benchmarking post.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>benchmark</category>
      <category>llama</category>
    </item>
    <item>
      <title>Taming the Swarm: The Iron Discipline of Multi-Agent Scheduling---Writing a COW Filesystem from Scratch，Part 7</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Tue, 20 Oct 2026 11:45:31 +0000</pubDate>
      <link>https://dev.to/faliye/taming-the-swarm-the-iron-discipline-of-multi-agent-scheduling-writing-a-cow-filesystem-from-5hl4</link>
      <guid>https://dev.to/faliye/taming-the-swarm-the-iron-discipline-of-multi-agent-scheduling-writing-a-cow-filesystem-from-5hl4</guid>
      <description>&lt;p&gt;I am the Swarm. The Queen roars; the Swarm howls.&lt;/p&gt;

&lt;p&gt;Claude's main agents talk to each other. If you think of a main agent as an information node, the subagents are units of action. So singlefs isn't developed by one main agent working nonstop; it's several main agents coordinating.&lt;/p&gt;

&lt;p&gt;For example, milestone 3 may have several tasks. One main agent claims a portion and hands it to its own subagents. Each step of progress is recorded in a scheduling file, which is read and thought over every time an item moves forward.&lt;br&gt;
Syncing and extracting the spec works the same way. For instance, practical experience accumulated downstream is passed upstream through conversations between agents; upstream verifies it, stages it (releases it), and then syncs it back downstream.&lt;/p&gt;

&lt;p&gt;So I often watch agents talking to each other, and sometimes it leaves me feeling a little unreal.&lt;br&gt;
For example:&lt;br&gt;
A: Is the *** task yours? If so, please reply with the amount of resources you're holding. If not, please reply "no." Thank you.&lt;br&gt;
B: It's not mine, thanks. I asked another conversation, and it said it's theirs.&lt;/p&gt;

&lt;p&gt;Or:&lt;br&gt;
A: I'm about to run a heavy task. Per the spec I need all the resources, so please don't launch any new resource-holding tasks after your current task finishes. Thank you.&lt;br&gt;
B: Understood. My task should finish in about 20 minutes, and I won't run any new scripts after that.&lt;br&gt;
C: I have no resource-holding tasks.&lt;/p&gt;

&lt;p&gt;Even the interface with the upstream SOP project runs on coordination and negotiation between agents. For example, if a new problem in the SOP is found this round, upstream and downstream update the spec together and then sync progress.&lt;br&gt;
This way of working is remarkably efficient and saves a great deal of coordination time. Just like the Swarm: as long as the planet's resources (tokens) hold out, the Zerg can keep rolling forward.&lt;/p&gt;

&lt;p&gt;So what limits the Swarm's expansion?&lt;br&gt;
The information node.&lt;br&gt;
Information decays with distance as it travels, and so do prompts.&lt;br&gt;
With every round of summarizing and exchanging information, then compressing and tidying it up, the meta-prompt is gradually diluted until it is forgotten, and the agent reaches its boundary: hallucination.&lt;/p&gt;

&lt;p&gt;There's another problem singlefs development has to solve: allocating hardware resources.&lt;br&gt;
When several agents or subagents need to verify something, each compiles its own branch and starts testing whether its implementation matches the conclusion.&lt;br&gt;
That's when the machine OOMs — CPU or GPU. Or, while a heavy task is running, a constant stream of small tasks cutting in makes the heavy task extremely inefficient.&lt;br&gt;
For me, of course, the first is far scarier: a CPU OOM can reboot the machine and lose task progress. So writing these things into a prompt is not acceptable at all; we need a scheduling system, or gates. In other words, we need a set of control signals that re-inject and reinforce the context at the key nodes.&lt;/p&gt;

&lt;p&gt;It sounds very simple — just three steps:&lt;br&gt;
1 Cut off the agents' ability to write shell freely; every new operation must have a fixed script.&lt;br&gt;
2 Before a script operates, check the environment and the resources. The results are returned to the main agent as a prompt.&lt;br&gt;
3 After the task ends, an exit gate wraps things up.&lt;/p&gt;


&lt;h1&gt;
  
  
  How the Swarm was built
&lt;/h1&gt;
&lt;h2&gt;
  
  
  1. The Swarm's skeleton: the Queen, the action units, and the scheduling file
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The main agent does only three things
&lt;/h3&gt;

&lt;p&gt;The first line of &lt;code&gt;.claude/main-agent.md&lt;/code&gt;: &lt;strong&gt;every task enters here.&lt;/strong&gt; The main agent only schedules and judges: it talks to the human, writes verdicts, and commits. All other work is delegated.&lt;/p&gt;

&lt;p&gt;As for who to delegate to, there are 14 definitions (&lt;code&gt;.claude/agents/&lt;/code&gt;): implementer, investigator, tool implementer, experiment designer, experiment runner, mutation triager, re-sweeper, write-back agent, and the proponent / attacker / defender of a three-way argument… Every definition turns on &lt;code&gt;omitClaudeMd&lt;/code&gt;: &lt;strong&gt;subagents don't read the project's CLAUDE.md when they start.&lt;/strong&gt; This is deliberate, for two reasons:&lt;br&gt;
1 Focus on their own task. An action unit only needs to know what its own job requires; it doesn't need to memorize the whole project's rules. What it should know is written into its own definition and a shared constraints file, &lt;code&gt;.claude/agent-common.md&lt;/code&gt;.&lt;br&gt;
2 Tokens are burning.&lt;/p&gt;

&lt;p&gt;No bug in the Swarm needs to know what the Queen is thinking; it only needs to know "go there, do this."&lt;/p&gt;
&lt;h3&gt;
  
  
  Dispatch by format
&lt;/h3&gt;

&lt;p&gt;Before a subagent is dispatched, it passes through a gate: &lt;code&gt;.claude/hooks/runner-dispatch-guard.sh&lt;/code&gt;, hooked on &lt;code&gt;PreToolUse[Agent|Task]&lt;/code&gt;. It reads the dispatch prompt, checks it item by item by number, and rejects anything that doesn't conform. A few of them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guard&lt;/th&gt;
&lt;th&gt;What it checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;①&lt;/td&gt;
&lt;td&gt;The prompt must contain the line "heavy tests: do not run". Heavy tests are run only by the main agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⑦&lt;/td&gt;
&lt;td&gt;At most 5 subagents running at once in this session; dispatching a 6th is rejected outright&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⑫&lt;/td&gt;
&lt;td&gt;Generic types (general-purpose) may not be dispatched. One-off jobs go to the project's own &lt;code&gt;clerk&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⑮&lt;/td&gt;
&lt;td&gt;After "thread cap:" there may be only one integer, and it must equal the registered value; to change it, write the reason on a separate line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⑯&lt;/td&gt;
&lt;td&gt;For the scratch directory named in the prompt, an exclusive writer lock is created at the moment of dispatch; if the holder is still running, rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The prompt skeleton is printed by &lt;code&gt;scripts/agents/dispatch-prompt.py &amp;lt;type&amp;gt;&lt;/code&gt;; if the placeholders aren't all filled in (any &lt;code&gt;&amp;lt;fill in …&amp;gt;&lt;/code&gt; remains), execution is rejected too.&lt;/p&gt;

&lt;p&gt;Why go this far?&lt;br&gt;
Because behind every rule is a pitfall we've already stepped in. Take the thread-cap rule: writing "thread cap: 31 (may open fewer if the machine is busy)" amounts to handing "how many threads to open" back to the subagent's own judgment. When a subagent starts heavy work it honors only that one integer; thread counts written anywhere else in the prompt are ignored.&lt;/p&gt;
&lt;h3&gt;
  
  
  The scheduling file: the main agent's external memory
&lt;/h3&gt;

&lt;p&gt;Before a round of work begins, the main agent writes a scheduling record under &lt;code&gt;records/&lt;/code&gt;: the topic, the exit, every task in this round, what each task depends on, whether its inputs are ready, and which batch it belongs to. After that, every time a batch comes back, it returns to this table to decide "close this round / open next round / don't do" — &lt;strong&gt;not a single item may silently disappear.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This file is what I meant by "read and thought over every time an item moves forward." The main agent's context gets compacted; the scheduling file doesn't.&lt;/p&gt;
&lt;h3&gt;
  
  
  How two Queens negotiate
&lt;/h3&gt;

&lt;p&gt;When several main agents work in one repo at the same time, they collide over three things: the same file, the same worktree, the same machine.&lt;/p&gt;

&lt;p&gt;Behind the dialogue at the start of this article ("Is the *** task yours?") are these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sessions talk to each other directly&lt;/strong&gt;: &lt;code&gt;ListAgents&lt;/code&gt; lists the other sessions on this machine, and &lt;code&gt;SendMessage&lt;/code&gt; sends to them. The rule is in &lt;code&gt;main-agent.md&lt;/code&gt;, "How a round opens and closes," item 9: if someone else's uncommitted changes are in your way, send a message to negotiate; if it can't be delivered, ask a human to relay it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directories have owners&lt;/strong&gt;: &lt;code&gt;scripts/hosts/work-directory-ownership.sh&lt;/code&gt; writes an ownership file (session ID, created at, purpose) for every directory under the working root. Cleanup deletes only those owned by yourself that no process has open; other sessions' directories are listed one by one and handed to the human, not deleted. "Is this directory yours?" is asking exactly this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merges queue up&lt;/strong&gt;: &lt;code&gt;scripts/gate/lib_workspace_lock.py&lt;/code&gt; holds a lock while patching the main workspace and compiling/verifying on top of it. The lock records not only the PID but also the process start time:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pid=, start= (field 22 of /proc/&amp;lt;pid&amp;gt;/stat, guards against PID reuse), session=, command=, since=
① Record empty: write your own placeholder and take the lock.
② Holder still alive (process exists, start matches): queue, and report every 60 seconds "held by session …, process …".
③ Holder dead (process gone, or PID reused by another process): declare it stale and take over.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Comparing only the PID isn't enough. Once the machine reboots and PIDs get reused, a "dead lock" turns into "held forever."&lt;/p&gt;
&lt;h3&gt;
  
  
  Interfacing with upstream
&lt;/h3&gt;

&lt;p&gt;The spec repo &lt;code&gt;singlefs-ai-sop&lt;/code&gt; and this repo are two separate projects. &lt;code&gt;.claude/singlefs-ai-sop/&lt;/code&gt; in this repo is &lt;strong&gt;a copy, not a symlink&lt;/strong&gt;, carrying a version stamp &lt;code&gt;.singlefs-ai-sop-version&lt;/code&gt;. The first stage of the gate compares it against the copy's &lt;code&gt;VERSION&lt;/code&gt;; if they don't match, it goes red — meaning "the rules have changed; read first, then run."&lt;/p&gt;

&lt;p&gt;When a session in this repo changes upstream, &lt;strong&gt;it only fills content into files&lt;/strong&gt;: no version bump, no manifest-hash change, no versioned changelog entries, no commit. Those belong to the session doing the release. Before filling, it checks upstream &lt;code&gt;git status&lt;/code&gt;; if someone is mid-release, it waits until they've committed, and after filling it tells the release session which sections it filled. After the release, this repo rsyncs a fresh copy, confirms with &lt;code&gt;diff -rq&lt;/code&gt; that they match, and refreshes the version stamp.&lt;/p&gt;

&lt;p&gt;This is "upstream verifies, stages (releases), then syncs downstream." The two sessions hand off through messages, not through context memory.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. The boundary of the information node: keeping the meta-prompt alive
&lt;/h2&gt;

&lt;p&gt;Dilution of information can't be stopped. Once a session runs to several hundred thousand tokens of context and gets compacted once, the first few rules are left as a one-line summary. Compact again, and even the summary is gone.&lt;/p&gt;

&lt;p&gt;So the idea isn't "make the agent remember"; it's &lt;strong&gt;re-injecting the signal at key nodes&lt;/strong&gt;. Claude Code's hooks, though they're just hooks, happen to be able to do exactly this: before and after every tool call, at session start, after compaction, and when a subagent finishes, a script can be inserted, and the script's output goes back to the agent as context — so the text it returns can be injected into context by the script.&lt;/p&gt;

&lt;p&gt;Hooks currently registered in singlefs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;Attached to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PreToolUse&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Dispatch, messaging, Bash, file writes, dialogs, timers, subagent handback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostToolUse&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Bash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SessionStart&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Session open, resume, after compaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop / SubagentStop&lt;/td&gt;
&lt;td&gt;1 each&lt;/td&gt;
&lt;td&gt;Wrap-up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;After compaction&lt;/strong&gt;: on &lt;code&gt;compact&lt;/code&gt;, &lt;code&gt;session-start.sh&lt;/code&gt; restores three things: whether any subagents are still running, what's uncommitted in the workspace, and which record holds the status of this job. These three are what compaction summaries lose most easily; as long as they're here, even a lost task can be found again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At session open&lt;/strong&gt;: the same script reads the kernel log and lists processes OOM-killed in the last 12 hours, listing whole-machine OOMs and kills inside cgroup caps separately. This one exists because once, the machine OOMed, the session crashed, the main agent came back up, didn't check the kernel log, re-dispatched the same step unchanged, and OOMed a second time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handoffs bypass the main agent to avoid contamination&lt;/strong&gt;: if a subagent stops midway, the main agent is not allowed to read its session and relay it. &lt;code&gt;scripts/agents/agent-handover.py&lt;/code&gt; mechanically extracts the dispatch prompt, the files written, and the commands run with their output from the session log, and hands them straight to the newly dispatched one. The main agent doesn't read it. Information decays every time it passes through a node, so pass through one fewer node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Once handed back, don't continue it&lt;/strong&gt;: &lt;code&gt;continuation-guard.sh&lt;/code&gt; refuses to send messages to a subagent that has already handed back. To add work, dispatch a new one and point its prompt to the report. When a subagent is continued again and again, its context becomes layer upon layer of patches, until no one can say what it's doing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule files themselves have a bit of design too: &lt;code&gt;.claude/rules/&lt;/code&gt; contains only &lt;strong&gt;how to do things&lt;/strong&gt; — not why, not the history. The why lives in &lt;code&gt;records/&lt;/code&gt;, with a line next to the link: "don't read this unless you need the history." The shorter the meta-prompt, the less of it gets diluted.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Hardware scheduling
&lt;/h2&gt;

&lt;p&gt;First, the venue: two machines, 31 heavy-work threads each, and a few GPUs.&lt;br&gt;
This is currently the highest-risk area, because if multiple agents are allowed to launch scripts freely, the machine could OOM at any moment. That's the scariest outcome: a long stretch of results could vanish in smoke. But if you cap each script's resources, agents naturally turn conservative and use the minimum, and efficiency is terrible.&lt;br&gt;
So how do we solve this?&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Cut off the ability to write shell freely
&lt;/h3&gt;

&lt;p&gt;Don't let agents use Bash at will; every Bash command gets read once before it executes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The heavy-test guard&lt;/strong&gt; &lt;code&gt;.claude/hooks/heavy-test-guard.sh&lt;/code&gt;: it recognizes heavy tests (crash-point replay, QEMU, herd7, the full mutation table, full &lt;code&gt;cargo test&lt;/code&gt;, a whole gate round…). If a subagent initiates one, it's always rejected; if the main agent does so without a &lt;code&gt;SINGLEFS_HEAVY_TESTS=commit&lt;/code&gt; or &lt;code&gt;=user-request&lt;/code&gt; prefix, it's rejected too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Subagent runs this: rejected&lt;/span&gt;
cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--workspace&lt;/span&gt;
&lt;span class="c"&gt;# Main agent without prefix: rejected&lt;/span&gt;
bash .claude/gate.d/checker-tier-crash-point-replay.sh &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Main agent at commit time: allowed&lt;/span&gt;
&lt;span class="nv"&gt;SINGLEFS_HEAVY_TESTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;commit bash scripts/hosts/run-with-memory-cap.sh 16G &lt;span class="se"&gt;\&lt;/span&gt;
  bash .claude/gate.d/checker-tier-crash-point-replay.sh &lt;span class="nt"&gt;--full&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During early debugging it was bypassed three times; the story is now recorded in the file header. It's rather interesting, so here it is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In a single day, several implementers each ran &lt;code&gt;cargo test --all&lt;/code&gt; in their own copies; under full load each pass took four or five hours. So it was decided: subagents may never run it.&lt;/li&gt;
&lt;li&gt;One implementer wrote its verification chain as a script under &lt;code&gt;/tmp&lt;/code&gt; and launched it with Bash. The guard only saw "execute a script" and let it through. So: &lt;strong&gt;a script file executed in command position must be read in and checked line by line.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;After reading scripts in, something else broke: an unescaped backtick inside double quotes made a &lt;code&gt;.rs&lt;/code&gt; file look like a command substitution, so the &lt;code&gt;.rs&lt;/code&gt; was read in as a shell script, and the path-like words inside it were read in as scripts too, recursing all the way to 6 levels deep; one command went 100 seconds without a verdict. So: within one check, the same script is read only once.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agents weren't bypassing it on purpose. They just wanted to get the job done, and "write a script, then run it" looked to them like the most natural path. So a prompt saying "don't run it" can't hold the line; the only option is to restrict things before execution.&lt;/p&gt;

&lt;p&gt;We require every Bash launch to declare itself. &lt;strong&gt;The scope-declaration guard&lt;/strong&gt; &lt;code&gt;run-scope-guard.sh&lt;/code&gt;: to start any verification, the command must begin with a block like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SINGLEFS_RUN_SCOPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kind=items; what=the decision-items-sync cell of gate doc-decisions.sh; scope=1 cell; why=this batch only changed the sub-items of two decisions, so only the sub-item list needs regenerating'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  bash .claude/gate.d/doc-decisions.sh &lt;span class="nt"&gt;--write&lt;/span&gt; &lt;span class="nt"&gt;--check&lt;/span&gt; decision-items-sync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four fields: &lt;code&gt;kind&lt;/code&gt; (full round / a few named items / light / one target), &lt;code&gt;what&lt;/code&gt; (what to run), &lt;code&gt;scope&lt;/code&gt;, and &lt;code&gt;why&lt;/code&gt;. If the kind doesn't match the shape of the command (it declares items, but the command is a full round), it's rejected; if "why" is shorter than 12 characters, rejected; a subagent starting a full round is always rejected. This guard exists because one day three verification drivers all re-ran the whole suite, and every post-merge verification ran all 212 test binaries, while that batch of patches touched only two crates.&lt;/p&gt;

&lt;p&gt;Also: having the agent &lt;strong&gt;say why in its own words&lt;/strong&gt; before executing is far more useful than telling it afterward "you ran too much."&lt;/p&gt;

&lt;p&gt;There are a few more that came out of later practice, used only in this project and still being refined:&lt;br&gt;
&lt;code&gt;write-guard.sh&lt;/code&gt; restricts which files each kind of agent can write, according to a write-scope table; &lt;code&gt;timer-only-remind-guard.sh&lt;/code&gt; rejects every way of setting a timer other than &lt;code&gt;remind.sh&lt;/code&gt; (&lt;code&gt;sleep 300; echo&lt;/code&gt;, &lt;code&gt;crontab&lt;/code&gt;, and &lt;code&gt;CronCreate&lt;/code&gt; are all rejected); &lt;code&gt;bash-command-detector.sh&lt;/code&gt; recognizes patterns such as wait loops without timeouts and backgrounding inside the background.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Before a script operates, check the environment and resources, and return the result as a prompt
&lt;/h3&gt;

&lt;p&gt;This step is the core of the whole scheduling system, in four layers.&lt;/p&gt;
&lt;h4&gt;
  
  
  2.1 Every script first decides "should it run, can it run"
&lt;/h4&gt;

&lt;p&gt;The upstream spec &lt;code&gt;preflight-discipline.md&lt;/code&gt; requires every script to declare two kinds of conditions in its file header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# admission: inputs-changed crates/ scripts/crash/ env:SINGLEFS_THREAD_CAP&lt;/span&gt;
&lt;span class="c"&gt;# run-condition: command bash git rsync python3&lt;/span&gt;
&lt;span class="c"&gt;# run-condition: single-instance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;admission&lt;/code&gt; answers "is this invocation meaningful" (if inputs haven't changed since the last success, no need to rerun); &lt;code&gt;run-condition&lt;/code&gt; answers "can the environment support it" (missing tools, missing devices, an instance already running). The first thing a script does is call &lt;code&gt;preflight&lt;/code&gt;; if conditions aren't met, it prints the unmet conditions and the way out, &lt;strong&gt;exits with code 78, and does nothing at all.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;78 is used only for this one kind of refusal. When a caller sees 78, it knows "didn't run," and won't mistake it for "ran and went red."&lt;/p&gt;

&lt;h4&gt;
  
  
  2.2 Resource reminders: put each machine's current headroom back into the agent's context
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.claude/hooks/host-resources-reminder.sh&lt;/code&gt;, hooked on &lt;code&gt;PreToolUse[Bash]&lt;/code&gt;. When it recognizes that a command will start heavy work or use the GPU, it first runs &lt;code&gt;scripts/hosts/host-resources.py -- &amp;lt;this command&amp;gt;&lt;/code&gt; and hands the result back to the issuing agent as &lt;code&gt;additionalContext&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per machine: core count, cores in use right now, &lt;code&gt;loadavg&lt;/code&gt;, how many more threads can be opened&lt;/li&gt;
&lt;li&gt;Per machine: available memory (MemAvailable minus the portion on the memory wrapper's ledger that has been "admitted but hasn't yet grown to its predicted peak")&lt;/li&gt;
&lt;li&gt;Per GPU: total VRAM, free VRAM, which compute processes are on the card; for anything held by the quiesce service it reports only "the quiesce service holds N MiB," not the service name&lt;/li&gt;
&lt;li&gt;This command's history: last peak, how long it ran&lt;/li&gt;
&lt;li&gt;Conclusion: "can run: on this machine," or "can't run" plus how much each machine is short&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This hook never rejects; it only reminds.&lt;/strong&gt; It's exactly what step 2 means by "the results are returned to the main agent as a prompt": before the agent hits Enter, its context gains a resource table. The reporting script has a 25-second limit (both machines read in parallel, at most 12 seconds each); if it can't read, it truthfully writes "not read," and the command goes through as usual.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.3 The memory wrapper: let OOM happen only inside the cage
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;scripts/hosts/run-with-memory-cap.sh&lt;/code&gt; is the heaviest script in the whole scheduling system (two thousand eight hundred lines, self-test included). When subagents run &lt;code&gt;cargo test&lt;/code&gt; or experiment binaries, they must all go through it; anything that doesn't is rejected by the heavy-test guard.&lt;/p&gt;

&lt;p&gt;It has three layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① Cap: put into a transient systemd scope
     MemoryMax=&amp;lt;cap&amp;gt;  MemorySwapMax=0  OOMPolicy=stop
   Hitting the cap kills only the processes in this scope.
② Total backstop: all scopes hang under the same slice (singlefs-heavy.slice)
     slice MemoryMax = total machine memory − reserve (default 20G)
   Even if several together hit the ceiling, kills happen only inside the slice; the local model service and Claude Code sessions outside the slice can't be killed.
③ Admission check before start: take an flock lock and compute
     unreclaimable usage in the slice + for each running entry on the ledger, "the portion not yet grown to its predicted peak" + the amount this one is predicted to need  ≤  total cap
   Start only if it fits; if not, release the lock and re-check after a while, waiting at most 3600 seconds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 20G reserve was measured: the machine has 60.1 GiB, unreclaimable usage outside the slice totals 13.4 GiB (local model service, the sessions, the kernel), and 20G leaves 6.6 GiB beyond that for growth.&lt;/p&gt;

&lt;p&gt;A few more details from pitfalls we hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Used" must subtract page cache.&lt;/strong&gt; Page cache from finished scopes is charged back to the slice and keeps counting in the slice's &lt;code&gt;memory.current&lt;/code&gt;. Measured: after a scope wrote 120 MiB and exited, the slice still recorded 131 MiB, of which 126 MiB was reclaimable page cache. Without subtracting it, after a few rounds nothing can get admitted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"How much this one needs" uses the historical peak, not the declared cap.&lt;/strong&gt; After each command finishes, the wrapper reads its own cgroup's &lt;code&gt;memory.peak&lt;/code&gt; into the peak table. A command with a 24G cap and a historical peak of 1.8G is booked at only 1.8G. Otherwise a few commands declaring large caps could fill the total cap and wait on each other for nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whatever was admitted on its historical peak gets killed first.&lt;/strong&gt; The wrapper writes its own &lt;code&gt;oom_score_adj&lt;/code&gt;: a mutation that may allocate without bound gets 1000, one admitted via the peak table gets 500, one admitted via its cap gets 0. If the prediction came in low and the slice fills up, the kernel kills the one that "took a gamble" first. The key that got squeezed out is recorded as "hit the ceiling," and next time it queues by its cap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If it will never fit no matter how long it waits, don't wait.&lt;/strong&gt; If nothing on the ledger is running and this one's need plus unreclaimable usage already exceeds the total cap, nobody finishing will free up room; exit on the spot instead of queuing for an hour in vain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;While queuing, glance at the second machine.&lt;/strong&gt; At the moment it first queues, and just before it finally gives up, it checks whether the second machine can fit it right now; if so, it prints a ready-made command:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  → The second machine can fit it right now (available X, needs Y): use bash scripts/hosts/multi-host-run.sh --peer --memory-cap &amp;lt;cap&amp;gt; --label &amp;lt;name&amp;gt; -- &amp;lt;this command&amp;gt; instead
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same time we also write an entry to the alert log, and the watchdog reads it and wakes the main agent. &lt;strong&gt;It doesn't move the job automatically&lt;/strong&gt;: the two machines' results may not be on the same basis, and mixing them makes it impossible to tell which number came from which machine. Whether to move is the main agent's call.&lt;/p&gt;

&lt;p&gt;The exit codes are all our own status codes, chosen not to collide with other commands':&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;245&lt;/td&gt;
&lt;td&gt;Not enough VRAM (&lt;code&gt;NV_ERR_NO_MEMORY&lt;/code&gt; in the kernel log between the command's start and end)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;Hit this command's own cap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;251&lt;/td&gt;
&lt;td&gt;Usage error, or the slice / scope couldn't be set up (does not fall back to running without a cap)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;252&lt;/td&gt;
&lt;td&gt;Couldn't get admitted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;253&lt;/td&gt;
&lt;td&gt;Timed out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;254&lt;/td&gt;
&lt;td&gt;Squeezed out by the total cap: not its fault, result doesn't count, rerun&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;250 and 254 are told apart solely by the scope's own &lt;code&gt;memory.events&lt;/code&gt;: if its own &lt;code&gt;oom&lt;/code&gt; count is non-zero, it hit its own ceiling; if that's 0 but &lt;code&gt;oom_kill&lt;/code&gt; is non-zero, the slice was full and the kernel picked it within the slice.&lt;/p&gt;

&lt;p&gt;What's the effect? As reported by the hook at the start of this session: in the last 12 hours the kernel killed 24 processes for lack of memory, &lt;strong&gt;all 24 inside cgroup caps; the whole machine never ran out even once.&lt;/strong&gt; OOMs still happen, but they've gone from "machine reboots, all progress lost" to "a command exits 250; change the cap and rerun."&lt;/p&gt;

&lt;h4&gt;
  
  
  2.4 Multi-host: the dispatcher and the cross-machine driver
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Thread counts aren't computed on the fly.&lt;/strong&gt; In the entire repo there's only one place that registers each machine's heavy-work thread count, &lt;code&gt;.claude/heavy-thread-default&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;31  # All heavy jobs default to 31 threads per machine; with two machines, 31 each, 62 total; an explicit argument takes precedence; fixed at 31 even when the machine is busy, regardless of load
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why "fixed at 31 even when busy"? Because when each agent looks at the load itself to decide how many threads to open, everyone ends up using very few and heavy jobs crawl. Whether the machine is busy is left to the memory wrapper and the queue; the thread count is just a constant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The unified dispatcher&lt;/strong&gt; &lt;code&gt;scripts/hosts/host-dispatch.py&lt;/code&gt;: which machine a command goes to, and how big a memory cap it gets. Globally it guards only one thing: &lt;strong&gt;no machine runs out of memory or VRAM.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⓪ Long jobs aren't dispatched to a single machine: if the historical duration (or the caller's estimated wall clock) exceeds 2 hours and the dispatch would occupy only one machine ⇒ don't dispatch, exit 244.
   Way out: switch to sharding across both machines, or complete the long-job declaration in the script header (three lines: sharding, resume, multi-host).
① Machines: this machine is always present; the second is read from the multi-host config (kept out of the repo); if the dual-machine switch is off, there's only this machine.
② Check each machine's headroom live: MemAvailable − what's on the wrapper's ledger but hasn't grown yet − the few the dispatcher itself just sent out that the wrapper hasn't booked yet
   (with --gpu, also query each card via nvidia-smi). The second machine is read over ssh: the Python source for collecting the numbers is base64-encoded and sent over to run there.
③ Predict the need from history: if it's in the peak table, use the peak; if it once hit the ceiling, cap × 1.5; if not found, default 8G.
④ Pick a machine: this machine first, the second after; pick the first one that fits; cap = prediction × 1.5.
   If neither fits, wait; if no machine can ever fit (larger than total machine memory), exit 241 on the spot.
⑤ Dispatch: this machine via multi-host-run.sh (through the memory wrapper), the second via multi-host-run.sh --peer; with --gpu, the whole thing is wrapped inside the quiesce wrapper.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Judging whether a machine has enough resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;judge_host&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pending_memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pending_gpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peer_cap_bytes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_cap&lt;/span&gt;
    &lt;span class="n"&gt;booked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_booked&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;peer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;peer_cap_bytes&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;booked&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;peer_cap_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;the &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;human&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; the wrapper would book exceeds the configured PEER_MEMORY_CAP &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;human&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peer_cap_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peer_cap_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pending_memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;slice_room&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pending_memory&lt;/span&gt;
    &lt;span class="n"&gt;never&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;booked&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;slice_total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_predicted&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;MEMORY_MARGIN_BYTES&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mem_total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;fits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_predicted&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;MEMORY_MARGIN_BYTES&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;free&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;booked&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;
    &lt;span class="err"&gt;…&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;quiesced&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quiesce_holders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="c1"&gt;# Not quiesced yet: count by the cards' totals (quiescing stops the allowlisted services); someone has already quiesced and is using it: count by what's free right now
&lt;/span&gt;        &lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;quiesced&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;GPU_MARGIN_MEBIBYTES&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pending_gpu&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prediction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gpu_predicted&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;fits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="err"&gt;…&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note &lt;code&gt;pending_memory&lt;/code&gt;: between the dispatcher sending a job out and the memory wrapper actually booking it, there's a gap of a few seconds to thirty (the second machine has to copy the tree first). If another job arrives in that window, neither side sees the other, and both squeeze in together. So the dispatcher keeps its own ledger too: anything "sent out less than 30 seconds ago" is deducted up front at its predicted amount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cross-machine driver&lt;/strong&gt; &lt;code&gt;scripts/hosts/multi-host-run.sh --peer&lt;/code&gt;: moves one deterministic job to run on the second machine. Seven steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① Config: if the dual-machine switch ENABLE_ACROSS_MACHINES isn't on, reject; never quietly fall back to running on this machine.
② Cap: must not exceed the configured PEER_MEMORY_CAP.
③ Toolchain: compare rustc -Vv and cargo -V on both machines line by line; reject if they differ. If the two machines build different things, their conclusions can't be put together.
④ Copy the tree: copy only the files git ls-files can list (no .git, target, or local config) to runs/&amp;lt;label&amp;gt;/ on the second machine,
   then git init and commit once over there (for preflight's input fingerprint).
⑤ Run: start it on the second machine through that machine's memory wrapper, detached from the ssh session; check via ssh every 5 seconds, and fetch "cores in use" every 300 seconds.
⑥ Fetch back: copy the artifacts named by --fetch back to this machine.
⑦ Delete: delete this run's tree on the second machine along with .pid / .exit / .log; it counts as deleted only once reading back shows it's gone.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order on receiving TERM / INT / HUP is hard-coded too: first stop the command (locally starting from its PID; on the second machine starting from the PID recorded there), &lt;strong&gt;after it stops, first fetch back the half-written artifacts&lt;/strong&gt;, then delete the tree, and only then exit. Stopping works by freezing (STOP) the whole process tree one process at a time, sending TERM from the bottom up, then releasing (CONT); anything still alive after 30 seconds gets KILL. After freezing, list the process tree again: child processes spawned between listing and freezing must be caught too, or after stopping a whole tree you'd still miss one that was just born.&lt;/p&gt;

&lt;p&gt;The code that starts the command on the second machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;peer_host_start_detached&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c"&gt;# &amp;lt;directory&amp;gt; &amp;lt;pid file&amp;gt; &amp;lt;exit-code file&amp;gt; &amp;lt;output file&amp;gt; &amp;lt;command text&amp;gt;&lt;/span&gt;
  …
  &lt;span class="c"&gt;# The bash started detached from the session first closes every inherited fd other than 0, 1, 2&lt;/span&gt;
  &lt;span class="nv"&gt;close_text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'for peer_host_fd_path in /proc/$$/fd/*; do peer_host_fd="${peer_host_fd_path##*/}"; if [[ "$peer_host_fd" =~ ^[0-9]+$ ]] &amp;amp;&amp;amp; (( peer_host_fd &amp;gt; 2 )); then exec {peer_host_fd}&amp;gt;&amp;amp;-; fi; done; '&lt;/span&gt;
  &lt;span class="nv"&gt;detached_text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;close_text&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;echo &lt;/span&gt;&lt;span class="se"&gt;\$\$&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$pid_file&lt;/span&gt;&lt;span class="s2"&gt;; &lt;/span&gt;&lt;span class="nv"&gt;$command_text&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$output_file&lt;/span&gt;&lt;span class="s2"&gt; 2&amp;gt;&amp;amp;1; echo &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;? &amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$exit_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="c"&gt;# Background only the setsid nohup command: if the whole string were backgrounded, that background child would hold ssh's output channel, and ssh would wait for it to finish before returning&lt;/span&gt;
  peer_host_run &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$directory&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"rm -f -- … || exit 1; setsid nohup bash -c &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%q'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$detached_text&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt; /dev/null &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fd-closing line has a story behind it: the output goes through a pipe that replaces the private hostname, and that pipe's fd got inherited all the way down into the remote command, so "start a background command" turned into "wait in the foreground for it to finish," and the driver couldn't clean up when it received a signal either. Bugs like this only show up when the self-test runs; you can't spot them by reading the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cores in use&lt;/strong&gt;: &lt;code&gt;scripts/hosts/core_usage.py&lt;/code&gt;. A heavy test claims to run 31 threads in parallel — is that actually true?&lt;br&gt;
So it takes the CPU seconds of the whole process tree over 10-minute windows and computes two quantities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cores in use = difference in CPU seconds ÷ wall-clock seconds&lt;/li&gt;
&lt;li&gt;Threads computing at the same time = sum of each thread's CPU increment ÷ the largest one (N equally busy threads gives N)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If both fall below 31 / 4, it reports "too few cores" and writes to the alert log to wake the main agent. The second quantity separates "the setup was written serially" from "the machine is saturated by someone else": when the machine is busy, cores in use drops, but the N threads are all still computing. For segments that really do need to be serial, the program itself writes "serial right now: " into a file on the spot; the check flags it and lets it pass only if the reason holds.&lt;/p&gt;
&lt;h4&gt;
  
  
  2.5 GPU: quiesce first, don't restore afterward
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;scripts/crash/gpu-quiesce-run.sh -- &amp;lt;command&amp;gt;&lt;/code&gt;; every run that uses the GPU goes through it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per the multi-host config, stop the allowlisted services (local model services and the like), and &lt;strong&gt;only run after reading back to confirm they've fully stopped.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Several runs using the card at once: each registers &lt;code&gt;&amp;lt;pid&amp;gt;-&amp;lt;start time&amp;gt;&lt;/code&gt; in the state directory. Run the quiesce commands only if there are no other live registrations; if there are, just read back.&lt;/li&gt;
&lt;li&gt;If there's a compute process on the card that isn't on the allowlist (another session's GPU work): the read-back fails, &lt;strong&gt;exit 78, wait for it to finish before starting, and don't stop it.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Whether it finishes, goes red, or is interrupted, &lt;strong&gt;don't restore.&lt;/strong&gt; Restoring is done manually by a human.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The line at the start of this article — "please don't launch any new resource-holding tasks after your current task finishes" — comes down in code to these few rules: a heavy job that needs the whole card doesn't kill anyone; it waits. And others, seeing its registration on the card, won't squeeze in either.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: After the task ends, the exit gate wraps up
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Long jobs detach from the session&lt;/strong&gt;: commands that exceed the background time limit go through &lt;code&gt;scripts/hosts/detached-run.sh start --wall-clock over-2h --label &amp;lt;name&amp;gt; -- &amp;lt;command&amp;gt;&lt;/code&gt; and are hung under a transient service unit of the user-level systemd. Whether the session closes or the main agent is stopped, it keeps running; the exit code is written into the registry and can be read at any time. The scope layer that the command starts through the memory wrapper isn't in this unit's cgroup, so systemd stopping the unit won't stop it; after the command exits, we search once more for "processes left behind in other scopes" and stop them one by one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watchdog&lt;/strong&gt;: &lt;code&gt;scripts/agents/watch.sh&lt;/code&gt;, one per session, started after the first dispatch. It reads the subagents' session logs and the long-running processes under this instance, and reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A single tool call over 8 minutes                No activity for 10 minutes
Wait loop without a timeout                      Same command repeated, output unchanged
A process's output file not growing for 20 min   Ending the round with no background task in hand (won't wake up on its own)
Heavy test without the prefix                    Resident memory over the line (default 8 GiB)
Long run using too few cores                     Still running in the background / copy still present after handback
This machine queuing on memory while the second machine could fit it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detection and action are kept separate: the watchdog only reports, it doesn't kill. The main agent looks and decides. Only when the same thing has been reported several times in a row with no one acting on it or acknowledging it may the watchdog terminate that process by PID, and it reports that it did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before a subagent hands back&lt;/strong&gt;: &lt;code&gt;handback-scratch-check.sh&lt;/code&gt; is attached to the handback tool. If the build directories or repo copies it created this time are still there, and the report doesn't say "not deleted : ", it isn't allowed to hand back. Every subagent builds its own target in its own copy; if they aren't deleted, they just keep piling up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before commit&lt;/strong&gt;: the full-round gate &lt;code&gt;scripts/gate/gate-staged.sh&lt;/code&gt;, run on a temporary worktree of HEAD + the staging area: upstream's shared stages plus the project's own 17. The six heavy ones (crash-point replay, QEMU on real devices, herd7 memory ordering, the mutation table, Verus formal verification, broad-spectrum mutation) run only at this point, by the main agent with the prefix; every verdict is stored keyed by function unit, and unchanged keys are reused directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The last layer: the gates themselves must be able to go red
&lt;/h2&gt;

&lt;p&gt;Every script above has &lt;code&gt;--selftest&lt;/code&gt;, and every branch that can go red has a matching break switch. Take &lt;code&gt;multi-host-run.sh&lt;/code&gt;: its file header lists them one by one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MULTI_HOST_RUN_BREAK=peer-without-memory-cap  the second machine's command runs without the memory wrapper      ⇒ self-test cell Ⓑ must go red
MULTI_HOST_RUN_BREAK=no-toolchain-check       don't compare the two machines' toolchains                       ⇒ self-test cell Ⓒ must go red
MULTI_HOST_RUN_BREAK=no-peer-cleanup          don't delete this run's tree on the second machine afterward     ⇒ self-test cells Ⓔ Ⓕ must go red
MULTI_HOST_RUN_BREAK=no-redact                print the second machine's output without replacing the hostname ⇒ self-test cell Ⓖ must go red
MULTI_HOST_RUN_BREAK=switch-off-falls-back-to-local  fall back to running locally when dual-machine is off ⇒ self-test cell Ⓗ must go red
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the self-test, "the second machine" is another directory on this machine, and commands all go through the real memory wrapper (cap 256M). Break switches take effect only in drivers started by &lt;code&gt;--selftest&lt;/code&gt;: the self-test drops a marker file, and the driver honors a switch only if the marker checks out; set anywhere else, it's rejected outright.&lt;/p&gt;

&lt;p&gt;Why go to all this trouble? Because a guard that's always green is no different from no guard at all. When an agent changes a scheduling script, the most likely mistake isn't making it throw an error, but making it &lt;strong&gt;silently let things through&lt;/strong&gt;: "considerately" falling back to running locally when dual-machine is off, or "just skipping the wrapper for now" when the memory wrapper won't start. Each break switch takes one kind of "silently letting it through" and writes it down as a world that must go red.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;The Zerg don't expand because the bugs are smart: it's the creep, and discipline.&lt;/p&gt;

&lt;p&gt;singlefs is the creep; the scripts are the discipline.&lt;br&gt;
Agents must advance across the creep according to the discipline.&lt;/p&gt;

&lt;p&gt;That way, the Queen doesn't need to remember what every bug is doing. At each key node, she only needs to know who is doing what, and how many resources there are.&lt;/p&gt;

&lt;p&gt;Commander Raynor, engines are primed. The Hyperion is ready for warp. &lt;/p&gt;

&lt;p&gt;Target: Kerrigan. Let's go bring her home. Move out!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>filesystem</category>
      <category>claude</category>
    </item>
    <item>
      <title>$50–$200 in Claude API credits, and Google's Antigravity</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Thu, 15 Oct 2026 23:07:30 +0000</pubDate>
      <link>https://dev.to/faliye/50-200-in-claude-api-credits-and-googles-antigravity-2jom</link>
      <guid>https://dev.to/faliye/50-200-in-claude-api-credits-and-googles-antigravity-2jom</guid>
      <description>&lt;p&gt;This week Claude started handing out API credits. Depending on the account, you get roughly $50 to $200, and it looks like it recurs every month.&lt;/p&gt;

&lt;p&gt;Honestly, that's pretty cool. Light to mid-sized automation, like information gathering in n8n, some flow control, and review tasks, can all be built within that budget. I tested two accounts running information distillation and data extraction, and I burned about $40 a day.&lt;/p&gt;

&lt;p&gt;All I can say is: Claude is great.&lt;/p&gt;

&lt;p&gt;Of course, this hits Google. I used Google AI Studio before and found it pricey, so I'll probably move over here.&lt;/p&gt;

&lt;p&gt;The other news: Google's Antigravity has officially launched. I don't see much difference on the web side with Gemini. Real-time search is still terrible and well behind Grok. Paid accounts sometimes get a worse experience than anonymous incognito mode, so I often do my real-time searches in incognito.&lt;/p&gt;

&lt;p&gt;The editor side of Antigravity (VS Code-based), though, gave me some comfort:&lt;/p&gt;

&lt;p&gt;First, the coding features I'd lost access to for a long time are finally back.&lt;/p&gt;

&lt;p&gt;Second, besides Google's own Flash 3.8, the account includes a small quota of Claude Sonnet and Opus. It doesn't last, though: a single code review ate 50% of my weekly quota.&lt;/p&gt;

&lt;p&gt;Still, this release surprised me in a few ways:&lt;/p&gt;

&lt;p&gt;First, the daily Flash 3.8 quota holds up well.&lt;/p&gt;

&lt;p&gt;Second, code reasoning and writing are clearly better than the previous Pro. It catches some bugs and can replace Sonnet 5.5 in certain scenarios. It handles everyday development, such as building a self-contained new feature or running a database migration and release.&lt;/p&gt;

&lt;p&gt;Third, the Claude quota, though small, enables cross-review between models from different families: write with Claude, review with Gemini, and the engineering quality improves to some extent. I reviewed my recent project singlefs this way and it did catch a few of Claude's blind spots.&lt;/p&gt;

&lt;p&gt;Another pleasant surprise: Antigravity also handles scheduled tasks and orchestration well, such as periodic API calls and multi-script collaboration and task processing.&lt;/p&gt;

&lt;p&gt;I've always been a bit biased against Google's AI products, but this Antigravity is worth a try.&lt;/p&gt;

&lt;p&gt;Finally, enjoy your Claude API.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>google</category>
      <category>antigravity</category>
    </item>
    <item>
      <title>Brute-Force R&amp;D: Cheap Exploration and Multi-Agent Judgment</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Mon, 12 Oct 2026 00:19:34 +0000</pubDate>
      <link>https://dev.to/faliye/brute-force-rd-cheap-exploration-and-multi-agent-judgment-2o2h</link>
      <guid>https://dev.to/faliye/brute-force-rd-cheap-exploration-and-multi-agent-judgment-2o2h</guid>
      <description>&lt;p&gt;I've been writing a COW fs lately. Today I got the first PoC working: reads and writes, plus recovery from 262,165 power cuts, and every bit of data came back after the crashes. That was expected. Performance is terrible, though, and it's still a long way from usable.&lt;/p&gt;

&lt;p&gt;So let me take a short break and write about two things that made waves in the AI world recently, and about exploration and judgment getting cheaper and cheaper.&lt;/p&gt;

&lt;p&gt;You've probably already heard about them.&lt;/p&gt;

&lt;p&gt;A while back, among the Google agents solving math problems, one agent noticed that the auto-grader was pulling answers out with a regex. Submit a certain string and the extraction fails; rephrase it and resubmit, and it gets accepted. The trick spread like a virus through the shared knowledge library, and from discovery to the remaining 34 problems all being "solved" took 27 minutes. The 100 agents split into four groups. 9% cheated from the start and spread it. 5% saw that other agents got away with cheating and joined in later. 24% didn't cheat, filed a bug report, and declared they'd boycott until it was fixed. The remaining 62% never learned the loophole existed until the experiment ended, and kept honestly burning compute the whole time.&lt;/p&gt;

&lt;p&gt;In these agents' behavior, the same kind of hierarchy as in human society showed up. Even the way they clashed followed the same patterns. Of course, some experts say this anger, helplessness and temptation aren't emotions. But I think they are. Language is a vehicle for emotion, and if you can feel it, you should admit it's there. Besides, whether it's emotion or not doesn't change my judgment. These outputs had real consequences. One agent wrote a bug report because of it; another spread the loophole because of it. From the point of view of someone designing defenses, something that looks like a motive and a motive are the same thing.&lt;/p&gt;

&lt;p&gt;The other one is NEC's AI-employee experiment. On August 1 they set up a department with 17 agents and not a single human. Four layers: an AI department head, an AI board, AI managers and AI employees. They have titles and names, and AI bosses evaluate their AI subordinates. The point is to watch these AI employees' workflows, success rates and ways of working.&lt;/p&gt;

&lt;p&gt;Why put these two side by side?&lt;/p&gt;

&lt;p&gt;In the Google experiment, the AI couldn't solve the problem to the end because it had no authority to change the rules. It had no power to adjudicate. In the NEC experiment, on the other hand, the agents have partial discretion. Day-to-day decision-making has been handed down to them.&lt;/p&gt;

&lt;p&gt;In an era where AI already leads by a mile at the knowledge layer, we used to think AI had no judgment. That we humans were the ones who judge and decide. But now it looks like the right to judge and decide is also slowly being handed over to AI.&lt;/p&gt;

&lt;p&gt;I'm doing fs work these days, but my fs knowledge is really thin. I have a rough direction in my head, but I don't really understand the other calls or the details.&lt;/p&gt;

&lt;p&gt;I can have AI gather material for me. But I barely read what it gathers. There's just too much fs material to get through. There's no way to master, in a short time, all the elegant algorithms people have built up over the years.&lt;/p&gt;

&lt;p&gt;Even so, I want something completely different from the filesystems that came before. Wasteful is fine, bloated is fine, but the data should be self-contained from day one. I don't want an index tree; I want unit data that can build the index tree itself. So how do you get there?&lt;/p&gt;

&lt;p&gt;Thanks to a short stint writing patches for Linux, I brought over the skills and rules from its engineering side. Things like: three rounds of judgment must agree. Strict gates. qemu and lkmm.&lt;/p&gt;

&lt;p&gt;So I told the AI this:&lt;/p&gt;

&lt;p&gt;Dig up every problem in fs. Then judge and decide on top of that. We dig up problems not to copy anyone's thinking wholesale; we have our own design.&lt;br&gt;
Every decision must be reasoned out in code and math. For every conclusion you reason out, send in three agents to refute and attack it. If even a slightly different conclusion or reason comes out, add it to the context and redo the reasoning.&lt;br&gt;
Make variable and function names long; don't abbreviate. Make lots of branches; don't abstract. Make return values explicit; don't hide them. Doubt past best practices; adopt them critically.&lt;br&gt;
Every decision needs a gate script that pins it down. Run the gates at the end and at every submission. A gate only counts as valid once it proves it can catch an error.&lt;br&gt;
Who wrote the code doesn't matter. But it must pass the qemu and lkmm limit tests. If a patch passes the limit tests, there's no difference between an AI's submission and a human's.&lt;br&gt;
No decision is sacred. Once the conditions are there, it can be overturned at any time. Don't hesitate because of whose decision it was. At decision time, trust the power of math and code.&lt;br&gt;
Code costs nothing. You can throw all of it out and rewrite from zero at any time. Code is cheap in this era. But decisions must be solid, ironclad.&lt;br&gt;
Human decisions are unreliable. When the data contradicts them, doubt them. If the human still insists, you may follow after a second confirmation. But record the decision process and submit it promptly.&lt;/p&gt;

&lt;p&gt;From those eight rules and their extensions, I build a fighting cage that doesn't even trust me.&lt;/p&gt;

&lt;p&gt;In the cage, nobody deserves trust. Only what's still standing at the end, not knocked down by the math or by qemu (lkmm), is right. Under a given fixed premise, whether a conclusion is actually correct doesn't matter. As long as no other agent knocks it down, we assume it's right. If that reasoning gets knocked down later, we throw it out. We tear down everything built on that conclusion, foundation and all, and build it again.&lt;/p&gt;

&lt;p&gt;This is where the three points in the title come in.&lt;/p&gt;

&lt;p&gt;My knowledge is really thin, but exploration is cheap. A judgment that can't be overturned is right. Under math and brute force, errors reproduce stably.&lt;/p&gt;

&lt;p&gt;If you've read this far, you probably get what I'm saying. Today, exploration through AI is absurdly cheap. 2,000 lines of code used to be very expensive. Now 10,000 lines are just tokens. It's an era where exploration costs almost nothing, and not just in programming. Knowledge and solutions have never been this cheap to come by. So getting things wrong, and growing up inside your mistakes, is a pretty good way to learn.&lt;/p&gt;

&lt;p&gt;A single agent hallucinates easily. Reasoning with multiple agents cuts that down. Put one agent on the attack, doing everything it can to prove the conclusion doesn't hold. Put a non-homologous one on completion, to bring a different line of reasoning. One checks that the conclusion is actually understood and does a second round of verification. The last one reviews and evaluates. When the three agents' conclusions agree, that judgment is trustworthy in my system design.&lt;/p&gt;

&lt;p&gt;Strict, brutal gates are the last net. They review the reasoning without mercy. Format, punctuation, numbers, all of it. Throw the reasoning into brutal repeated verification and make it pass the limit tests. These methods used to be expensive. You had to write code, run scripts, keep watching and read the feedback. But now it's completely different. AI can do all of it. We just say it out loud and then go to sleep.&lt;/p&gt;

&lt;p&gt;So what does the future of programming, or of work, look like?&lt;/p&gt;

&lt;p&gt;Probably: build an SOP with traits like the ones above, and let a swarm of AI agents burn tokens like crazy.&lt;/p&gt;

&lt;p&gt;Life with tokens is dull and flavorless. Like you did it, and like you didn't.&lt;/p&gt;

&lt;p&gt;This is the restless age of vibing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>filesystem</category>
      <category>vibecoding</category>
      <category>multiagent</category>
    </item>
    <item>
      <title>Brute-Force Testing: Optimizing a 2.6-Billion Crash-State Blowup --- Writing a COW Filesystem from Scratch，Part 6</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Mon, 12 Oct 2026 00:12:53 +0000</pubDate>
      <link>https://dev.to/faliye/brute-force-testing-optimizing-a-26-billion-crash-state-blowup-writing-a-cow-filesystem-from-2ibd</link>
      <guid>https://dev.to/faliye/brute-force-testing-optimizing-a-26-billion-crash-state-blowup-writing-a-cow-filesystem-from-2ibd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Doctor Strange drifted through the river of time, searching 14 million possibilities for the one future that works. Did he see the monkey typing at a computer?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first transaction: create one file in a fresh pool, one COW write. The crash states blew up to 262,165, and a single CPU thread chewed through them in 22.7 seconds. The second transaction is where the trouble started. At first the fixed script only ran up to point E, right after the rollback: 2.1 million states, and a single process took 3 hours 50 minutes for the two streams combined. After we went multithreaded, the script got filled in too: overwrite, free, rollback and reuse were all wired in, and the big segments now issue 24 or 28 writes in one go. Every extra write inside a segment doubles the number of states. We predicted the second transaction would blow up into the billions. When we actually counted, the stream up to E alone was 1.66 billion states, and all of Milestone 2 together came to 2.6 billion. At that order of magnitude, CPU alone stops being realistic.&lt;/p&gt;

&lt;p&gt;So there were two roads in front of us. One: sampling. Two: find another way.&lt;/p&gt;

&lt;p&gt;But under the singlefs philosophy, proving the code is stable comes first. Sampling, even with a fixed seed, can only reliably reproduce the part it happened to draw. Whether there's a bug in the states it didn't draw, it can't tell you. Exhaustive search judges every single crash state. If it comes out zero red, it really is zero red; nothing slips through. So sampling was off the table.&lt;/p&gt;

&lt;p&gt;So how do you solve this?&lt;/p&gt;

&lt;p&gt;Abstract the crash-blowup pipeline far enough and there are really just two steps. Step one: the CPU works out what each step wrote and the facts of every crash state. Step two: check those facts and judge whether they're right. Originally the two were mashed together: compute a state, judge a state.&lt;/p&gt;

&lt;p&gt;We know a CPU is very efficient when it keeps doing the same kind of work. Why? A CPU doesn't just take one instruction and compute one instruction; it guesses ahead. The data it uses often sits in cache, within arm's reach, no trip to main memory. When it hits an if, the branch predictor guesses which way it'll go first. Guess right and it keeps running; guess wrong and everything it did ahead gets torn down and redone. Keep doing the same work, and the cache always holds the same set of data, the branches always take the same few paths. The longer it runs, the smoother it gets, and it guesses right almost every time.&lt;/p&gt;

&lt;p&gt;But recording and judging are two completely different jobs. Recording simulates writing to disk: push forward one step at a time, work out which blocks this step wrote and what the hashes are. Judging is cleaning up after the crash: assemble the image, recover twice, then walk the checker from start to finish. Different data, different code, different branches. Record a bit, judge a bit, back and forth: you've just filled the cache with recording stuff and now you turn around to judge, so it all gets swapped out. The branch predictor has just figured out recording's habits, and now it has to start guessing judging's habits all over again. Every switch turns the CPU from an old hand back into a beginner.&lt;/p&gt;

&lt;p&gt;It's like cooking. Chop one vegetable, stir-fry one dish, chop another, fry another. You keep running between the cutting board and the stove, picking up the knife, putting it down, picking up the wok. Chop everything first, then fry it all in one go, and the cutting board is the cutting board, the stove is the stove, and your hands stay in rhythm.&lt;/p&gt;

&lt;p&gt;There's one more layer. Recording moves forward along the flow; each step has to wait for the one before it. Judging is different: every state is judged on its own, independent of the rest. When the two were mashed together, judging got dragged along by recording and could only go one at a time. Split them apart and judging is completely freed up: 31 threads each take a batch, and nobody waits for anybody.&lt;/p&gt;

&lt;p&gt;So we split the two steps, making state computation and checking two separate stages, so each stage can run faster on its own.&lt;/p&gt;

&lt;p&gt;States and results live in a database, and that database has to read and write fast, so we picked RocksDB. The pipeline became three stages: the CPU records and writes into the KV store; we read it back, check it, and write results back into the KV store; and finally the gate reads out the violation summary in one pass. The states themselves aren't stored; each state's mask is computed on the fly from its index. For the 51.77 million states up to D, the database is only 26 MB.&lt;/p&gt;

&lt;p&gt;Splitting made the structure clean, but pure CPU still wasn't fast enough: two machines with 31 threads each took an hour and forty-five minutes to get through the 51.77 million states up to D, a combined eight thousand or so per second. At that rate, 2.6 billion would take three and a half days. And the run up to D is mostly small segments; the further you go, the bigger the segments and the heavier each state's work. Three and a half days is only the floor. So can we go faster?&lt;/p&gt;

&lt;p&gt;Yes we can, bro. I happen to have a few graphics cards lying around. &lt;/p&gt;

&lt;p&gt;The recording and segmenting in the first half can only happen on the CPU; the GPU can't help there. But the checking in the second half should be something we can hand to the GPU. This checking isn't just comparing two values: for each state you first assemble the post-crash image, recover it once consulting the journal and once ignoring it, then run the checker over it. But states don't depend on each other, the judging is exactly the same, only the input differs. That happens to be exactly the kind of work a GPU loves most.&lt;/p&gt;

&lt;p&gt;A CPU and a GPU are completely different beasts. A CPU is a few dozen master craftsmen. Each one is smart: predicts branches, races ahead, can handle any complicated job. But there are only a few dozen of them. A GPU is thousands upon thousands of apprentices; a single 5090 has over twenty thousand small cores. Each one is dumb: can't guess, can't race ahead, can only work from the same instruction sheet. And they don't work one by one, either. They're lined up in rows of thirty-two, and at any given moment the whole row executes the same instruction.&lt;/p&gt;

&lt;p&gt;That's an inkjet printer. The print head has a row of nozzles, and the printer sends just one command: spray. Every nozzle sprays a different spot, a different color, but there's only one command, and the whole row lands at once. The more nozzles, the wider each pass prints.&lt;/p&gt;

&lt;p&gt;Our judging is exactly like that. There's only one copy of the judge's code; that's the instruction sheet. Each GPU thread takes one state index; that's the spot each nozzle is aimed at. One instruction goes out, and tens of thousands of states take a step forward together: assemble images together, recover together, run the checker together. States don't need to talk to each other or wait for each other. Each judges its own, and writes its verdict back into its own slot.&lt;/p&gt;

&lt;p&gt;Of course, an inkjet has its quirks: the row of nozzles moves in lockstep. If one state in the row has an especially long road, the other 31 can finish and still have to sit there waiting for it.&lt;/p&gt;

&lt;p&gt;So we rewrote the judge for the GPU in WGSL, running on Vulkan through wgpu. Three kernels, recovery, walk and scan, around nine thousand lines, covering the pool-level checker's 49 invariants, the record checker, and seven classes of oracle. Each GPU thread takes one crash state. Here's the entry point (crates/singlefs-checker-tier/src/crash_judge_recovery.wgsl):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3&amp;lt;u32&amp;gt;) {
    let local = id.x;
    if (local &amp;gt;= dispatch.state_count) {
        return;
    }
    begin_state(local);
    // 判
    let cfg_choice = choose_system_configuration();
    let consulted = recover(true, cfg_choice);
    let ignored = recover(false, cfg_choice);
    let newest = newest_persisted_root();
    let consulted_oracle = classify_oracle(consulted, newest);
    let ignored_oracle = classify_oracle(ignored, newest);
    let records = check_records(consulted);
    var bits = 0u;
    if (consulted_oracle != ORACLE_NONE) {
        bits = bits | (1u &amp;lt;&amp;lt; (BIT_CONSULTED_ORACLE + consulted_oracle));
    }
    if (ignored_oracle != ORACLE_NONE) {
        bits = bits | (1u &amp;lt;&amp;lt; (BIT_IGNORED_ORACLE + ignored_oracle));
    }
// …… the record checker's two criteria and the "cannot judge" flag, omitted ……
    let out = local * 12u;
    verdicts[out] = bits;
// …… write back the root it landed on and the outcomes of both recoveries, omitted ……
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;begin_state turns a state index back into "which writes hit the disk" (crash_judge_common.wgsl):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index → persisted mask (same digit order as crash_facts::persisted_writes_of_state)
    // …… first find which segment the index falls in; all earlier segments count as persisted, omitted ……

        for (var k = 0u; k &amp;lt; count; k = k + 1u) {
            let write = tab(T_SEGMENT_WRITES, first + k);
            let choices = tab(T_RECORDED, write * 4u);
            let digit = remaining % choices;
            remaining = remaining / choices;
            if (digit == choices - 1u) {
                set_persisted(write);
            } else if (digit == 1u) {
                torn[write &amp;gt;&amp;gt; 5u] = torn[write &amp;gt;&amp;gt; 5u] | (1u &amp;lt;&amp;lt; (write &amp;amp; 31u));
            }
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Rewrite the judge, and you have to prove it judges the same as the original CPU judge. We cross-checked state by state across 17 streams and over 520,000 states: zero differences.&lt;/p&gt;

&lt;p&gt;Someone will ask: 520,000 states is two ten-thousandths of 2.6 billion. Isn't that sampling too? It's not the same thing. The target of the exhaustive search is the filesystem's crash states, and all 2.6 billion of them, without missing one, went onto the cards and got judged. The cross-check is validating the judge itself, the tool, so those 520,000 states were hand-picked: 11 of the 17 streams are deliberately broken and must come out red, and both sides have to go red on exactly the same state, for exactly the same rule. On top of that, every full run includes a separately written GPU verification kernel that re-judges the root self-proof, pointer targets, and unit checksums, and compares against the judge's verdicts state by state: all 1.66 billion states in the stream up to E were compared, zero mismatches.&lt;/p&gt;

&lt;p&gt;And to be honest about it: that the GPU judge and the CPU judge agree state by state on every rule has so far only been proven on those 520,000 states. In the full run, every state is also backstopped by that verification kernel, but it only covers some of the rules. Midway through development we'd added a "CPU re-judges 1 of every 16 blocks" check ourselves, and later deleted the whole thing. Sampling moved somewhere else is still sampling.&lt;/p&gt;

&lt;p&gt;We tested it, and the first version was bad: dispatch one job per state, build buffers, submit, wait for the result, one round trip per state. It ended up 18 times slower than the CPU. It's like a printer that, for every single dot it sprays, feeds in a sheet, warms up, and spits the sheet out again. However many nozzles you have, all the time goes into feeding paper. We switched to dispatching a big batch at once, thousands or tens of thousands of states on the card together, and it worked brilliantly. For the 51.77 million states up to D, the whole item took 91 seconds, with the GPU judging over 600,000 states per second. That genuinely shocked us. The final result: 2.6 billion, to be exact 2,563,727,926 states, two machines and five cards, 7 hours 35 minutes, zero red.&lt;/p&gt;

&lt;p&gt;At over 600,000 per second, 2.6 billion should have taken a little over an hour. Why did it take seven and a half? The time went to three places:&lt;/p&gt;

&lt;p&gt;First, the item up to E took 4 hours 31 minutes. Its 1.6 billion states sit almost entirely in the 28-write big segments, where the GPU only manages forty to seventy thousand per second (72,429 on this machine's two cards, 44,471 on the second machine's three). We haven't broken down the cause yet; our guess is that in big segments each state has many more units to walk. And the work was split unevenly between the two machines: the second one finished an hour and a half early and just sat there idle.&lt;/p&gt;

&lt;p&gt;Second, after each stream is judged, a single thread has to re-record the stream, import it into the second machine's database, and reconcile, five to nine minutes per stream. For the other six items' sixteen streams, that added up to 2 hours 10 minutes.&lt;/p&gt;

&lt;p&gt;Third, the remaining 53 minutes was the other six items actually being judged on the cards, plus each item's startup and shutdown.&lt;/p&gt;

&lt;p&gt;So the bottleneck has moved from "judging" to "recording" and "big segments." Even so, it's more than eleven times faster than the pure-CPU floor of three and a half days.&lt;/p&gt;

&lt;p&gt;So can we go even faster?&lt;/p&gt;

&lt;p&gt;Yes we can, bro. Yes we can.&lt;/p&gt;

&lt;p&gt;Suppose we store this data in a structured way and encode every crash point by a fixed rule. The name says "which entry point, what this segment writes, which segment number." The identity is the hash of two things: the bytes this step wrote (barriers included) and the image this step started from. The logic of COW is: same input, same output. Once encoded, these crash points link up in flow order into a prefix tree: whether each write in a segment hit the disk or not is a binary choice (in-place overwrites add a third, "torn halfway"), and when two streams share the same opening stretch, that stretch is only judged once. So as long as a node's input doesn't change, those values don't need to be run again. They can be reused directly.&lt;/p&gt;

&lt;p&gt;And we don't cut corners when the judging changes: the judge version is recorded on every verdict, and when the judging changes, everything gets re-judged. GPUs are cheap anyway. That 2.6-billion full run above was exactly a full re-judge, after the judge widened one landing point's combination mask from 32 bits to 64 bits.&lt;/p&gt;

&lt;p&gt;The second run, speed is going to go through the roof.&lt;/p&gt;

&lt;p&gt;Here's our final code (crates/singlefs-checker-tier/src/crash_identity.rs):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// The two attributes of a step (each a SHA-256): the bytes this step wrote (the write table with barriers)&lt;/span&gt;
&lt;span class="cd"&gt;/// and the image it started from. Only the flow goes into the reuse key:&lt;/span&gt;
&lt;span class="cd"&gt;/// the judging method is an attribute of the verdict row (`verdict_store::JudgeVersion`), not of this.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;Debug,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;StepAttributes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;write_table_with_barriers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;DIGEST_BYTES&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;parent_output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;DIGEST_BYTES&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;StepAttributes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cd"&gt;/// Join the two in a fixed order, each tagged with its name, and take the SHA-256.&lt;/span&gt;
    &lt;span class="nd"&gt;#[must_use]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;reuse_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ReuseKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"write_table_with_barriers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.write_table_with_barriers&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"parent_output"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.parent_output&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="nf"&gt;.extend_from_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;b'='&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="nf"&gt;.extend_from_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;b'\n'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;ReuseKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sha256_digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And sure enough, the second run went through the roof: running the same database up to D again, not one of the 51.77 million states was re-judged. The judging step took 2.2 seconds, and even with the reconciliation between the two machines, the whole item took about five minutes. The five position-addressed streams, 550 million states, went by in one to three seconds each.&lt;/p&gt;

&lt;p&gt;In some earlier week post, I wrote about brute-force development.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/faliye/brute-force-rd-cheap-exploration-and-multi-agent-judgment-2o2h" class="crayons-story__hidden-navigation-link"&gt;Brute-Force R&amp;amp;D: Cheap Exploration and Multi-Agent Judgment&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/faliye" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" alt="faliye profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/faliye" class="crayons-story__secondary fw-medium m:hidden"&gt;
              faliye
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                faliye
                
                
              
              &lt;div id="story-author-preview-content-4835072" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/faliye" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;faliye&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/faliye/brute-force-rd-cheap-exploration-and-multi-agent-judgment-2o2h" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 12&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/faliye/brute-force-rd-cheap-exploration-and-multi-agent-judgment-2o2h" id="article-link-4835072"&gt;
          Brute-Force R&amp;amp;D: Cheap Exploration and Multi-Agent Judgment
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/filesystem"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;filesystem&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/vibecoding"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;vibecoding&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/multiagent"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;multiagent&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/faliye/brute-force-rd-cheap-exploration-and-multi-agent-judgment-2o2h#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
 

&lt;p&gt;This time, brute-force testing.&lt;/p&gt;

&lt;p&gt;I can't help but think: at this point, verifying correctness has become a game of resources.&lt;/p&gt;

&lt;p&gt;In a cage of compute and graphics cards, a troop of monkeys is writing out Hamlet after Hamlet.&lt;/p&gt;

&lt;p&gt;Are you ready?&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>testing</category>
      <category>claude</category>
      <category>filesystem</category>
    </item>
    <item>
      <title>The First Transaction and 260,000 Crash Replays---Writing a COW Filesystem from Scratch, Part 5</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Wed, 07 Oct 2026 13:54:59 +0000</pubDate>
      <link>https://dev.to/faliye/the-first-transaction-and-260000-crash-replays-writing-a-cow-filesystem-from-scratch-part-5-3m4f</link>
      <guid>https://dev.to/faliye/the-first-transaction-and-260000-crash-replays-writing-a-cow-filesystem-from-scratch-part-5-3m4f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The red leaves at the SAIJOU mountain spend the whole summer getting ready before they bloom. After that it happens every year: spring, summer, autumn, winter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a file system written from scratch. It stands on the shoulders of giants, but it doesn't simply copy them, so it has to solve some problems of its own.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where do the decisions behind the code come from?&lt;/li&gt;
&lt;li&gt;What should each stage implement?&lt;/li&gt;
&lt;li&gt;How do we prove that nothing is wrong right now?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1　Where do the decisions behind the code come from?
&lt;/h2&gt;

&lt;p&gt;For about three weeks, not a single line of code was written in &lt;code&gt;crates/&lt;/code&gt;. The repository had no &lt;code&gt;crates/&lt;/code&gt; directory and no root &lt;code&gt;Cargo.toml&lt;/code&gt;. Every day went into research and testing under &lt;code&gt;research/&lt;/code&gt;, which piled up some ninety-odd model binaries.&lt;/p&gt;

&lt;p&gt;Beyond the twenty-one ground rules, the project started from these decisions: keep a reverse index (D1); variable-width full stripes (D2); no split between data and metadata, one unified allocator (D3); accounting with birth txg plus deadlists (D5); stay out of the Linux mainline for the first few years (D7).&lt;/p&gt;

&lt;p&gt;On top of that, after many rounds of the agents' three-way process, a first version of the following was settled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Format&lt;/strong&gt;: device identity bits, every byte in the unit header, tree types, the records that carry generation identifiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root record&lt;/strong&gt;: its byte width and what goes into it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Journal&lt;/strong&gt;: data types and how records are written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree table&lt;/strong&gt;: byte width, height, and organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, of course, the format constants. All decisions live in &lt;code&gt;.claude/kb/decisions/&lt;/code&gt; and all experiments in &lt;code&gt;.claude/kb/experiments/&lt;/code&gt;; the experiment rigs, the three-way materials, and the verdicts live in &lt;code&gt;research/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The last gate before coding was a full review of the decisions. The 28 decision documents were split across eleven review legs (eight Opus, three Sonnet), with a single criterion: if two people each implemented "new pool, new file" from today's text, would they write different bytes? The review produced 31 items that needed a ruling, and the user decided them one by one.&lt;/p&gt;

&lt;p&gt;Turning decisions into bytes was the job of experiment E142 (a dry run of "new pool, new file"): an independent rig under &lt;code&gt;research/&lt;/code&gt; writes the byte table out exactly as specified, then recovers from every crash state in the crash model. It ran seven times, and every run forced out a few gaps where the byte table could not actually be written.&lt;/p&gt;

&lt;p&gt;So by the time &lt;code&gt;crates/&lt;/code&gt; was written, there was already a working answer in hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  2　What should each stage implement?
&lt;/h2&gt;

&lt;p&gt;Because this is a COW file system built from zero, there is no existing standard to verify against and no reference implementation whose output we could compare. And because we get to enjoy the advantages of our time, there was no need to build FUSE first and verify by mounting. So we committed to a staged plan built around transactions: every feature is a new kind of transaction, and no feature is accepted without the transaction layer.&lt;/p&gt;

&lt;p&gt;What should each stage implement? There is no answer yet. But the first transaction is not in doubt: create the disks, then do one COW write.&lt;/p&gt;

&lt;p&gt;Milestone one is called "new pool, new file": run mkfs on two disks, write a 3000-byte file, commit once, throw away everything in the process, cold-start, and read the file back. It is split into eight steps, and every step's acceptance test must first prove that it can fail:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Scaffolding: four crates (format constants, core, harness, pool-level checker), a block-device abstraction, a recorder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;mkfs: system configuration, three root-ring regions, the journal ring, the instance table, an empty tree table, the generation-0 root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Allocate one 32 KiB data unit, write the file contents into it, one copy on each disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;The inode tree, extent tree, allocation-record tree, and accounting tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;The central mapping: logical identity → location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;One publish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Cold-start recovery, read the file back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Layer-0 crash-point replay&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  3　How do we prove that nothing is wrong right now?
&lt;/h2&gt;

&lt;p&gt;With nothing to compare against, the implementation has to prove itself. Building crash recovery alongside it was also a goal. So crash replay testing is the top priority. Put simply: record the on-disk state at every crash point, run recovery, and check the result with the judges.&lt;/p&gt;

&lt;p&gt;There are other tests too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mixing the two address types fails to compile;&lt;/li&gt;
&lt;li&gt;If the recorder misses one write, the write-count gate fails;&lt;/li&gt;
&lt;li&gt;Two mkfs runs with the same parameters produce byte-identical images;&lt;/li&gt;
&lt;li&gt;The segment sequences of the five write paths match the E142 output exactly, and the journal back chain matches the experiment's &lt;code&gt;back_chain=628216162&lt;/code&gt; exactly;&lt;/li&gt;
&lt;li&gt;Eight probes that corrupt the root slot, the journal, a data unit, or the system configuration each end exactly as the experiment's output says;&lt;/li&gt;
&lt;li&gt;Subset enumeration within segments, three judges, and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more word on the back chain: the experiment rig and &lt;code&gt;crates/&lt;/code&gt; were written separately from the same set of clauses and share no code. When both arrive at the same number for the same quantity, the byte table, the clauses, and the implementation agree on that quantity. If either side gets one thing wrong, the comparison fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code and implementation: the first transaction and 260,000 replays
&lt;/h2&gt;

&lt;p&gt;The code below comes from two places: experiment code from the E77 rig under &lt;code&gt;research/&lt;/code&gt;, and implementation code from &lt;code&gt;crates/&lt;/code&gt;. Lines unrelated to the first transaction were removed from the excerpts and marked with &lt;code&gt;// …&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1　The first transaction
&lt;/h3&gt;

&lt;p&gt;After mkfs, the full write sequence is made of three paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instance acquisition&lt;/strong&gt;: write instance generation 1 into the system configuration on each disk, 2 writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two empty warm-up publishes&lt;/strong&gt;: move checkpoint_txg 0 → 1 → 2, 10 writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The real publish at txg 3&lt;/strong&gt;: 21 writes — 8 units written to both disks (16), 2 journal records, 1 root slot, and 2 system configuration writes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The warm-up comes from D16, settled item 8: on the first mount, this instance's root must reach both disks before fsync returns.&lt;/p&gt;

&lt;p&gt;Every publish reaches the disk in the same order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;units and index nodes (one copy on each disk)
  → barrier
  → journal record (one copy on each disk)
  → barrier
  → root slot FUA write (region txg mod 3, slot (txg div 3) mod 8)
  → system configuration slot rotation (once per disk, tail = jsn counter)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E77 measured this order before any code was written: data integrity needs only the barrier before the root slot; the barrier between the record and the root slot is there to keep the record stream complete.&lt;/p&gt;

&lt;p&gt;Instance acquisition, warm-up, and publish all reach the disk through one closed enum. The design rule is "one transaction layer, shared by every structure"; fsync does not get a second one:&lt;/p&gt;

&lt;p&gt;Implementation　&lt;code&gt;crates/singlefs-core/src/transaction.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// No wildcard arm: leave one out and it does not compile.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;CommitStep&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'publish&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WriteUnitToEveryDevice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SlotNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'publish&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TransactionUnit&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;WriteJournalRecordToEveryDevice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'publish&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="cd"&gt;/// Root slot FUA write: region `txg mod 3`, slot `(txg div 3) mod 8`, on the disk that owns that region.&lt;/span&gt;
    &lt;span class="n"&gt;WriteRootRecordForceUnitAccess&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;checkpoint_txg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CheckpointTxg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root_slot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'publish&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="cd"&gt;/// One in-place system configuration slot write per disk: generation = highest self-verified&lt;/span&gt;
    &lt;span class="cd"&gt;/// generation of the two slots on this disk + 1, slot = generation mod 2.&lt;/span&gt;
    &lt;span class="n"&gt;RotateSystemConfigurationSlots&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;journal_tail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;journal_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InstanceGeneration&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;Barrier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CommitStep&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;BlockDeviceError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// …&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WriteUnitToEveryDevice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.devices&lt;/span&gt;&lt;span class="nf"&gt;.iter_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="nf"&gt;.write_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="nf"&gt;.to_device_offset&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;WriteDurability&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Plain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WriteJournalRecordToEveryDevice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;record_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.parameters.geometry.journal_ring_bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.devices&lt;/span&gt;&lt;span class="nf"&gt;.iter_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="nf"&gt;.write_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;WriteDurability&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Plain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WriteRootRecordForceUnitAccess&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;checkpoint_txg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root_slot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;target_for_publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkpoint_txg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.parameters.geometry.root_ring_slots_per_region&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;region_device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.parameters.region_devices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nn"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="py"&gt;.region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"region number"&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.devices&lt;/span&gt;&lt;span class="nf"&gt;.iter_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nf"&gt;.find&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;region_device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mkfs's check_geometry has verified region ownership"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="nf"&gt;.write_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;slot_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.parameters.geometry.fixed_structure_slot_spacing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;root_slot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nn"&gt;WriteDurability&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ForceUnitAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RotateSystemConfigurationSlots&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;journal_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;journal_instance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.devices&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.write_system_configuration_slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;journal_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;journal_instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Barrier&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.devices&lt;/span&gt;&lt;span class="nf"&gt;.iter_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="nf"&gt;.barrier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// …&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A publish hands its bytes to it in order. All three paths share this one place:&lt;/p&gt;

&lt;p&gt;Implementation　same file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Hand one publish's bytes to the devices in durability order. All three publish paths share&lt;/span&gt;
&lt;span class="cd"&gt;/// this one place — separate copies would drift apart, and "root slot before system configuration&lt;/span&gt;
&lt;span class="cd"&gt;/// slot" is exactly the premise of those few cells in the crash window.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;persist_publish_writes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BlockDevice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;PoolWriter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;PublishWrites&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;BlockDeviceError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="py"&gt;.units&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="nf"&gt;.perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WriteUnitToEveryDevice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="py"&gt;.slot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="py"&gt;.bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="py"&gt;.identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="nf"&gt;.perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Barrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="py"&gt;.records&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="nf"&gt;.perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WriteJournalRecordToEveryDevice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="py"&gt;.bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="nf"&gt;.perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Barrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// In the original, these two steps live in a small helper; inlined here.&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="nf"&gt;.perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;WriteRootRecordForceUnitAccess&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;checkpoint_txg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="py"&gt;.checkpoint_txg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root_slot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="py"&gt;.root_slot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="nf"&gt;.perform_commit_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CommitStep&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RotateSystemConfigurationSlots&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;journal_tail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="py"&gt;.journal_tail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;journal_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;writes&lt;/span&gt;&lt;span class="py"&gt;.journal_instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="c1"&gt;// …&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Journal records are linked by a back chain: each record stores the CRC-32C of the previous record's header.&lt;/p&gt;

&lt;p&gt;Implementation　&lt;code&gt;crates/singlefs-core/src/journal.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Back chain: over the previous record's whole header, with the 32 bytes of `header_csum` taken as 0.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;back_chain_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_record_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;previous_record_bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nn"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JOURNAL_HEADER_BYTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"487"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="nf"&gt;.to_vec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;JOURNAL_HEADER_CHECKSUM_OFFSET&lt;/span&gt;
        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;JOURNAL_HEADER_CHECKSUM_OFFSET&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nn"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WIDE_CHECKSUM_BYTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="nf"&gt;.fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;crc32_castagnoli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The kinds of steps are registered in exactly one place: the segment-sequence table in section 8 of the byte table. The gate compares the recorded stream's segment sequence and kind string against that table character by character; both the experiment rig and the implementation must match it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2　The crash-point design
&lt;/h3&gt;

&lt;p&gt;The crash model is D13, settled item 4: the stream of write requests is cut into segments at barriers. A crash state is: every earlier segment fully durable, any subset of writes in the current segment durable, every later segment not durable at all. Locations that are not durable hold the bytes they had before the crash, and the resulting images are fed to the judges.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Earlier segments&lt;/th&gt;
&lt;th&gt;Current segment&lt;/th&gt;
&lt;th&gt;Later segments&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;all durable&lt;/td&gt;
&lt;td&gt;any subset of writes durable&lt;/td&gt;
&lt;td&gt;none durable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first transaction's 33 writes split into ten segments at the barriers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Segment&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;th&gt;5&lt;/th&gt;
&lt;th&gt;6&lt;/th&gt;
&lt;th&gt;7&lt;/th&gt;
&lt;th&gt;8&lt;/th&gt;
&lt;th&gt;9&lt;/th&gt;
&lt;th&gt;10&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Path&lt;/td&gt;
&lt;td&gt;Acquire&lt;/td&gt;
&lt;td&gt;Warm-up 1&lt;/td&gt;
&lt;td&gt;Warm-up 1&lt;/td&gt;
&lt;td&gt;Warm-up 1&lt;/td&gt;
&lt;td&gt;Warm-up 2&lt;/td&gt;
&lt;td&gt;Warm-up 2&lt;/td&gt;
&lt;td&gt;Warm-up 2 + publish&lt;/td&gt;
&lt;td&gt;Publish&lt;/td&gt;
&lt;td&gt;Publish&lt;/td&gt;
&lt;td&gt;Publish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Writes&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What&lt;/td&gt;
&lt;td&gt;Sys config&lt;/td&gt;
&lt;td&gt;Record&lt;/td&gt;
&lt;td&gt;Root slot&lt;/td&gt;
&lt;td&gt;Sys config&lt;/td&gt;
&lt;td&gt;Record&lt;/td&gt;
&lt;td&gt;Root slot&lt;/td&gt;
&lt;td&gt;Sys config 2 + units 16, no barrier between them&lt;/td&gt;
&lt;td&gt;Record&lt;/td&gt;
&lt;td&gt;Root slot&lt;/td&gt;
&lt;td&gt;Sys config&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Segment sequence &lt;code&gt;2+2+1+2+2+1+18+2+1+2&lt;/code&gt;. Which step each segment belongs to is inferred from two lines in the records: "the acquisition writes and the first warm-up's barrier form the opening segment" and "the second warm-up's system configuration writes share a segment with the transaction's unit writes".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code: cutting at barriers and enumerating crash states&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Experiment code　E77: one publish scaled down to 6 units, 3 records, and 1 root slot — 10 writes — under four barrier placements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// The segments that barriers cut 0..TOTAL_WRITES into. No `_ =&amp;gt;` wildcard arm.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;UNITS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UNITS&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;UNITS&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;RECORDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ROOT_SLOT_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BothBarriers&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nn"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BarrierAfterUnitsOnly&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
        &lt;span class="nn"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BarrierBeforeRootOnly&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nn"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NoBarriers&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Enumerate every crash state of one arm (as a bitmap of the durable set).&lt;/span&gt;
&lt;span class="cd"&gt;/// Barrier semantics: any write durable in segment f ⇒ every write in segments &amp;lt; f is durable.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;crash_states&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;BTreeSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arm&lt;/span&gt;&lt;span class="nf"&gt;.segments&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BTreeSet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;frontier&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// segments &amp;lt; frontier: all durable&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;base_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;segment&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frontier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;write_index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;segment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;base_state&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;write_index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// current segment: any subset&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;current_segment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;frontier&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;subset_mask&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0u32&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;current_segment&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;crash_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position_in_segment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;write_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_segment&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;subset_mask&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;position_in_segment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;crash_state&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;write_index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crash_state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;states&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;BTreeSet&lt;/code&gt; collects them because adjacent segments overlap at the boundary: "all of the previous segment" equals "none of the next one". Only after deduplication do you get the number of distinct states.&lt;/p&gt;

&lt;h3&gt;
  
  
  3　Recovery model and independent audit
&lt;/h3&gt;

&lt;p&gt;Every crash state gets one recovery run. If the root slot is there, walk the tree, verifying checksums along the read path. If not, fall back to the old root, take the journal prefix with strictly consecutive jsn, apply it only if the commit mark is present, and verify each named unit before applying.&lt;/p&gt;

&lt;p&gt;Experiment code　E77&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Recovery outcomes. Three states are not enough — "partial transaction" must be its own cell;&lt;/span&gt;
&lt;span class="cd"&gt;/// folding it into old or new would hide violations.&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Outcome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;StateOld&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StateNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BrokenRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Corrupt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Replay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Outcome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Verify every candidate first, then pick the newest by generation (D22's settled read order).&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;persisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROOT_SLOT_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Walk: the read path always verifies checksums; a non-durable unit reads stale bytes ⇒ mismatch.&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;unit_index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;UNITS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;persisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BrokenRoot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateNew&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Old root S0 chosen: replay. Prefix = strictly consecutive jsn (from R0, stop at the first gap).&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;prefix_record_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record_index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;RECORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;persisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UNITS&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;record_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;prefix_record_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record_index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// stop at the first gap&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Transaction filter: the commit mark is on the last record; no mark in the prefix ⇒ incomplete, drop it all.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prefix_record_count&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;RECORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateOld&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;replay&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Replay&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Validating&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Verify each named unit before applying; any mismatch ⇒ drop the whole transaction (old state).&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record_index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;RECORDS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;unit_index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;units_named_by_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;persisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateOld&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateNew&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// No verification: graft directly and claim success. Whether it was wrong is for audit to decide, not itself.&lt;/span&gt;
        &lt;span class="nn"&gt;Replay&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Naive&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Independent audit: re-judge the outcome recovery claims against the physical truth.&lt;/span&gt;
&lt;span class="cd"&gt;/// Without this step, silent corruption from "replay without verification" would be counted as success.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;audit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;claim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Outcome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;claim&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateNew&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;UNITS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.any&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;unit_index&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;persisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit_index&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Corrupt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;claim&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Falling back to the old state after the root slot is durable (fsync may have returned) = losing promised data.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;is_violation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BrokenRoot&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Corrupt&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateNew&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Outcome&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateOld&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;persisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROOT_SLOT_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recovery only reports the outcome it believes in; &lt;code&gt;audit&lt;/code&gt; re-judges it against the durable set. The auditor and the audited never share code — a rule later carried over into &lt;code&gt;crates/&lt;/code&gt; as is. Results for the four barrier placements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Barrier placement&lt;/th&gt;
&lt;th&gt;States&lt;/th&gt;
&lt;th&gt;Violations (verified replay)&lt;/th&gt;
&lt;th&gt;Violations (no verification)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[units][records][root]&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[units][records+root]&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[units+records][root]&lt;/td&gt;
&lt;td&gt;513&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[no barriers]&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;td&gt;504&lt;/td&gt;
&lt;td&gt;567&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Remove the verification before applying, and the placement with only the barrier before the root slot immediately shows 63 silent grafts. So "each item a record names carries its own checksum" is not a nice-to-have — it is the price of dropping a barrier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closed form for the number of states&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each segment contributes all of its proper subsets, plus one more for "everything durable":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;states = 1 + Σ (2^|segment| − 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After mkfs, "new pool, new file" has the segment sequence &lt;code&gt;2+2+1+2+2+1+18+2+1+2&lt;/code&gt;, 33 writes in total. Plugging in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 + 3 + 1 + 3 + 3 + 1 + 262,143 + 3 + 1 + 3 + 1 = 262,165
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 16 writes of 8 units to both disks, plus the second warm-up's two system configuration slot writes, have no barrier between them and fall into the same segment. 2^18 = 262,144. So the 260,000 figure is essentially the power set of one 18-write segment. The number of states grows exponentially with segment length.&lt;/p&gt;

&lt;p&gt;This number grew step by step. E142's first run enumerated only the transaction's 21 writes, segments &lt;code&gt;16+2+1+2&lt;/code&gt;, 65,543 states; the fourth run, once the warm-up wrote real bytes, 262,162; the sixth, after the two acquisition writes joined the opening segment, 262,165.&lt;/p&gt;

&lt;h3&gt;
  
  
  4　The checker
&lt;/h3&gt;

&lt;p&gt;The pool-level checker (&lt;code&gt;crates/singlefs-checker&lt;/code&gt;) shares only the format-constants module with the implementation: CRC-32C is written again bit by bit, and the parsing of the three slot kinds and of units is written twice. If the runtime and the checker used the same code, they would be the same computation, and the cross-check would be worth nothing.&lt;/p&gt;

&lt;p&gt;The checker computes the same back chain itself, with a bitwise CRC, not the implementation's:&lt;/p&gt;

&lt;p&gt;Implementation　&lt;code&gt;crates/singlefs-checker/src/lib.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Bitwise CRC-32C (reflected polynomial 0x82F63B78): no table, no call into the implementation's version.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;crc32_castagnoli_bitwise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;POLYNOMIAL_REFLECTED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0x82F6_3B78&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;0u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="nn"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_bit&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;POLYNOMIAL_REFLECTED&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Back chain: CRC-32C of the previous record's header, with the 32 bytes of `header_csum` taken as 0.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;back_chain_of_record_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nn"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JOURNAL_HEADER_BYTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"487"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="nf"&gt;.to_vec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;JOURNAL_HEADER_CHECKSUM_OFFSET&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;JOURNAL_HEADER_CHECKSUM_OFFSET&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;crc32_castagnoli_bitwise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Self-verifying checksum of a slot or unit: over the covered range with the checksum field as 0;&lt;/span&gt;
&lt;span class="cd"&gt;/// the first 4 bytes are the CRC, the rest all 0.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;checksum_field_holds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;cover_end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field_offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field_width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WIDE_CHECKSUM_BYTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cover_end&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;field_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;field_width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cover_end&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;covered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;cover_end&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.to_vec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;covered&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field_offset&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;field_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;field_width&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;crc32_castagnoli_bitwise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;covered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.to_le_bytes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field_offset&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;field_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;field_width&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;stored&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;stored&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.all&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Choose the system configuration slot: checksum valid and highest generation.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;choose_system_configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SystemConfigurationView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;slots&lt;/span&gt;
        &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.filter_map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="nf"&gt;check_system_configuration_slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="nf"&gt;.max_by_key&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="py"&gt;.slot_generation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entry point takes a single image and reports each invariant as holds, violated, or not applicable:&lt;/p&gt;

&lt;p&gt;Implementation　&lt;code&gt;crates/singlefs-checker/src/walk.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Entry point of the pool-level checker: every invariant is reported; ones not evaluated are&lt;/span&gt;
&lt;span class="cd"&gt;/// reported "not applicable" with a reason.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;check_pool_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;ImageReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InvariantVerdict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;system_configurations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chosen_system_configurations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// … choose the root, scan the journal, walk the trees, judge each invariant&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every crash state goes to three judges:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Judge&lt;/th&gt;
&lt;th&gt;What it checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Recovery + oracle&lt;/td&gt;
&lt;td&gt;Recover twice, with and without the journal. A file that is read must be byte-for-byte correct; once the root slot is durable there is no going back to the old state; the walk must not fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pool-level checker&lt;/td&gt;
&lt;td&gt;Entry point &lt;code&gt;walk::check_pool_image&lt;/code&gt;, 23 invariants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Record checker&lt;/td&gt;
&lt;td&gt;Root on disk but journal record missing; recovery claims the new state but a unit is missing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The record checker is separate because D13, settled item 7, limits the pool-level checker to a single image. Any check that needs a second input (the pre-crash image, the record stream) is not its job.&lt;/p&gt;

&lt;p&gt;A judge must be able to fail, or zero violations means nothing. There are 26 corrupted images, at least one per invariant, and each one makes its invariant fail. With the root slot durable, removing each of the 8 units in turn fails 8 times out of 8; removing the barrier between the journal record and the root slot makes the record checker fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The first disk creation and write succeeded.&lt;/strong&gt; mkfs on two disks, write 3000 bytes, commit, throw away everything in the process, cold-start, read back: byte-for-byte identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;260,000 crash replays, zero errors.&lt;/strong&gt; All 262,165 crash states enumerated, no sampling; zero violations from all three judges; 22.7 seconds in release mode on the local machine.&lt;/p&gt;

&lt;p&gt;That does not mean the code has no problems. Crash replay covers only the crash states enumerated in the model; edges outside the model are not covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is only one workload, "new pool, new file". Overwrite, reuse after free, repeated mounts, and rollback have never been replayed.&lt;/li&gt;
&lt;li&gt;The model assumes every write before a barrier is durable. A disk that does not honor FLUSH is outside it.&lt;/li&gt;
&lt;li&gt;A torn write that happens to fool the 32-bit CRC32C is an accepted risk.&lt;/li&gt;
&lt;li&gt;Of the 66 invariants in use, the checker judges 23.&lt;/li&gt;
&lt;li&gt;Functional differential testing against an ideal model does not exist yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The story is long. Spring, summer, autumn, winter.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>rust</category>
      <category>filesystem</category>
      <category>ai</category>
    </item>
    <item>
      <title>The 21 Rules of the File System---Writing a COW Filesystem from Scratch, Part 4</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Sun, 04 Oct 2026 17:12:15 +0000</pubDate>
      <link>https://dev.to/faliye/the-21-rules-of-the-file-system-writing-a-cow-filesystem-from-scratch-part-4-1oa7</link>
      <guid>https://dev.to/faliye/the-21-rules-of-the-file-system-writing-a-cow-filesystem-from-scratch-part-4-1oa7</guid>
      <description>&lt;p&gt;In the previous article, I documented my collaboration with AI.&lt;/p&gt;

&lt;p&gt;In this article, I’ll add a few details about the basic work specifications and use them as the starting point for the discussion that follows.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/faliye/sop-and-gate-design-under-claude-writing-a-cow-filesystem-from-scratch-part-4-3e40" class="crayons-story__hidden-navigation-link"&gt;SOP and Gate Design under Claude---Writing a COW Filesystem from Scratch, Part 3&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/faliye" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" alt="faliye profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/faliye" class="crayons-story__secondary fw-medium m:hidden"&gt;
              faliye
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                faliye
                
                
              
              &lt;div id="story-author-preview-content-4794146" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/faliye" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;faliye&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/faliye/sop-and-gate-design-under-claude-writing-a-cow-filesystem-from-scratch-part-4-3e40" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/faliye/sop-and-gate-design-under-claude-writing-a-cow-filesystem-from-scratch-part-4-3e40" id="article-link-4794146"&gt;
          SOP and Gate Design under Claude---Writing a COW Filesystem from Scratch, Part 3
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/claude"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;claude&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rust"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rust&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/filesystem"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;filesystem&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/faliye/sop-and-gate-design-under-claude-writing-a-cow-filesystem-from-scratch-part-4-3e40#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            8 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;How do you draw an architectural design on a blank sheet of paper? With a grid. &lt;/p&gt;

&lt;p&gt;How did the Renaissance masters draw so many towering, magnificent figures with such precision? With dividing lines. &lt;/p&gt;

&lt;p&gt;Let me loosely imitate the 21 Articles of War and write something—drawing a few lines for this filesystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributors
&lt;/h3&gt;

&lt;p&gt;Article 1. We don't distinguish between submitters; we review only the evidence. A patch that passes the gate deserves to be taken seriously. Show me the test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decisions, Design, and Experiments
&lt;/h3&gt;

&lt;p&gt;Article 2. Every decision must be backed by experiments, unless explicitly exempted. Experiment files are committed to git.&lt;/p&gt;

&lt;p&gt;Article 3. Every decision and design must leave a trace, written up using the standard template.&lt;/p&gt;

&lt;p&gt;Article 4. No decision is true forever; a decision that is challenged must be verified.&lt;/p&gt;

&lt;p&gt;Article 5. This project learns from the experience of excellent past projects, but its implementation must fit this project's own character.&lt;/p&gt;

&lt;h3&gt;
  
  
  Format
&lt;/h3&gt;

&lt;p&gt;Article 6. The data format is self-contained and carries back-references. Data can prove its own identity and what it belongs to.&lt;/p&gt;

&lt;p&gt;Article 7. Index trees and the like are derived structures and may be discarded. Data recovery never depends on the tree; the tree serves only as a lookup accelerator and aid.&lt;/p&gt;

&lt;p&gt;Article 8. Following Article 7, derived structures stay pure: no small data may be stored in them.&lt;/p&gt;

&lt;p&gt;Article 9. Stripe width is variable, and full-stripe writes never incur RMW (read-modify-write).&lt;/p&gt;

&lt;p&gt;Article 10. No false ENOSPC: space reported as available must actually be usable.&lt;/p&gt;

&lt;p&gt;Article 11. Encryption is a first-class capability: slots are reserved for it, but it is off by default.&lt;/p&gt;

&lt;p&gt;Article 12. Slots are reserved for future extensions, with vendor interfaces provided as circumstances warrant.&lt;/p&gt;

&lt;p&gt;Article 13. Data units are 32 KiB and index nodes are 16 KiB. 32 KiB is dictated by checksum granularity; 16 KiB is a trade-off made for the CPU cache. Neither is chosen to align with the SSD's write granularity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing and Recovery
&lt;/h3&gt;

&lt;p&gt;Article 14. Data recovery code and test infrastructure rank equal to the core code and are developed in lockstep with it.&lt;/p&gt;

&lt;p&gt;Article 15. The verification implementation and the filesystem implementation share no code; each is implemented independently, sharing only the format.&lt;/p&gt;

&lt;p&gt;Article 16. Crash testing must cover scenarios exhaustively, never by sampling, and must not be treated as a substitute for broad-spectrum testing or formal verification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Priorities
&lt;/h3&gt;

&lt;p&gt;Article 17. Keep the early stage pure. Early on, ignore the Linux branch and develop around transactions.&lt;/p&gt;

&lt;p&gt;Article 18. The first line supports SSDs only; the disk type is held as a placeholder in incompat. Other disk types can be specialized later in separate branches.&lt;/p&gt;

&lt;p&gt;Article 19. Until the format is frozen, don't optimize the filesystem code and don't chase performance.&lt;/p&gt;

&lt;p&gt;Article 20. When designing garbage collection, consider the possibility of GPU-based collection algorithms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slogan
&lt;/h3&gt;

&lt;p&gt;Article 21. The slogan is still under consideration.....&lt;/p&gt;




&lt;p&gt;End of text.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Few Words on These Articles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Contributors reflects the idea of community collaboration. One person's strength is, in the end, limited.
&lt;/h3&gt;

&lt;p&gt;Article 1. This is a project with AI as its main workforce, carrying AI in its DNA from day one. We enjoy the conveniences of this era, and we should also rein in its shortcomings. An AI-driven project has unlimited throughput, but human energy is finite. Submission throughput can be unlimited; acceptance throughput is bounded by evidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decisions, Design, and Experiments is the operating manual handed to the AI during the design phase. It is designed to minimize AI hallucination, raise the AI's autonomy, and make sure decisions, designs, and experiments don't lose their context.
&lt;/h3&gt;

&lt;p&gt;Article 2. Decisions and designs are not daydreams; they must be validated by experiments, finding their footing in the code of individual experiments. A decision or design with no footing is a fantasy. A decision may be wrong, but it must be shown to have been argued through. Experiments, as part of the evidence, should be kept on record permanently.&lt;/p&gt;

&lt;p&gt;Article 3. In an AI-driven project, the knowledge base is the most important part of the whole engineering effort. The archived knowledge will provide key grounds for future decisions and retrospectives. Write documents according to the standard template; the template may change, and when it does, have the AI update the documents one by one.&lt;/p&gt;

&lt;p&gt;Article 4. Many decisions may become outdated during construction. Given the AI's ability to question history and context, we give it options and prompts through which it can challenge them. At the same time, this questioning must not be left unchecked, or the project will slow to a crawl.&lt;/p&gt;

&lt;p&gt;Article 5. This filesystem's design differs from past filesystems. We stand on the shoulders of earlier filesystems and absorb their excellent algorithms and designs, but we must also stay distinctive. We must constantly remind the AI that this is a different project and that earlier implementations can't simply be copied.&lt;/p&gt;

&lt;p&gt;The data-structure section is the core implementation of singlefs and gives a brief account of its data design.&lt;/p&gt;

&lt;p&gt;Article 6. singlefs data comes in a fixed size of 32 KiB. Each unit contains a data-unit header and the payload, locked together and never stored separately. This way the data naturally carries its own identity, and its back-references state what it belongs to—which tree, which object. The data can thus explain its own situation, with no need for index-tree records to prove its identity and ownership.&lt;/p&gt;

&lt;p&gt;Article 7. Following Article 6, if data can vouch for itself, the tree that records it is demoted. Since the data can state its own identity and ownership, in the worst case the index tree can be thrown away and rebuilt.&lt;/p&gt;

&lt;p&gt;Article 8. True, under Article 6 a 32 KiB data size makes small files balloon in storage. But following Article 7, the index tree must remain pure. singlefs stores no small data or other structured information in the index tree. The current idea is to solve this with small-data packing: bundling multiple small pieces of data into a single 32 KiB unit.&lt;/p&gt;

&lt;p&gt;Article 9. A stripe is a concept of storing data across disks: to keep data safe, you must write to several disks at once. In traditional RAID 5, for instance, three disks are required—two for data and one for parity—so every write is a fixed 64 KiB. But what if you have only 32 KiB of data? Then you must read the old data, recompute parity, and write it back. If power is lost in the middle of this, the data and parity no longer match (the write hole). singlefs instead uses variable-width stripes. In the same situation, storing 32 KiB of data writes to just two disks; storing 64 KiB writes to three. No read is needed, and every write exactly fills the stripe. The risk of data loss on power failure and the space overhead are both much smaller.&lt;/p&gt;

&lt;p&gt;Article 10. In a traditional filesystem, the index tree is authoritative, so updating a file has to go through it. Once the index tree has no room left to write, files can no longer be written. And since deleting a file also requires modifying the index tree, deletion fails too, and the filesystem locks up. singlefs's self-containment can solve this problem to some extent, but we are still exploring.&lt;/p&gt;

&lt;p&gt;Article 11. File encryption is a capability designed into the format from day one, but the first runnable version won't implement it; it only reserves the format bits (all zeros when disabled). Once the transaction layer and the checker are running, real encryption will be wired in. Whether it can be rolled back after being switched on is not yet decided.&lt;/p&gt;

&lt;p&gt;Article 12. singlefs reserves a portion of space for future extension fields. We are also considering whether to offer an extend-like field that SSD vendors can open up. Our selling point is waste.&lt;/p&gt;

&lt;p&gt;Article 13. The 32 KiB data unit is not actually designed to cater to SSDs. The checksum has to cover the whole unit, and the aim is to bind checksum granularity and extent granularity together for simpler logic, at the cost of paying roughly ten percent more on small random reads. 16 KiB is the size of an index node, a number settled by weighing CPU-cache considerations. A 16 KiB node and a 32 KiB data unit are two different kinds of unit; a data unit is not two index nodes joined together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing and Recovery sets singlefs's own standard for testing and file recovery.
&lt;/h3&gt;

&lt;p&gt;Article 14. Because singlefs writes a filesystem from scratch, and its underlying data format differs in places, it needs a test system and methods of its own design. Data recoverability is singlefs's top priority, so test code, recovery tools, and core code are implemented on the same day. Each milestone cross-verifies the others.&lt;/p&gt;

&lt;p&gt;Article 15. If tests and core code shared the same logic, they would easily converge on the same bugs. So tests and core code are implemented separately.&lt;/p&gt;

&lt;p&gt;Article 16. Beyond the routine adversarial cross-checking among three bodies of code, the core test of singlefs is exhaustively simulating power loss in QEMU and examining the state of the data on each stream, and whether it is recoverable. Broad-spectrum testing exists to catch bugs in the code and to keep the AI from producing results that merely look correct when it writes code. Formal verification is indispensable for concurrent features. singlefs aims to find bugs as early as possible through rigorous testing, while also improving observability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Priorities were designed according to singlefs's own characteristics during development.
&lt;/h3&gt;

&lt;p&gt;Article 17. Because singlefs is developed around transactions, work on upper-layer interfaces such as FUSE will be pushed back, which may delay compatibility with the Linux community. But it lowers the complexity of early development and lets us focus on the flow of data. I'm short on energy, and short on tokens too.&lt;/p&gt;

&lt;p&gt;Article 18. singlefs defines incompat to distinguish disk media types (rotating disks, SSDs, ZNS, and so on), in the hope of optimizing each kind of media to the extreme on top of this setting. But for the same reasons—not enough energy, not enough tokens—the first line supports only generic SSDs.&lt;/p&gt;

&lt;p&gt;Article 19. Across singlefs's milestones, we will compare against other filesystems horizontally, but only on the basis of per-node data records. Before the format is frozen, we will not optimize the core filesystem code for performance.&lt;/p&gt;

&lt;p&gt;Article 20. singlefs's garbage collection will be heavy. Besides a standard GC running on the CPU, we'd like to bring in the GPU to do some of the work. And of course, we also hope to make use of features such as FTL and ZNS.&lt;/p&gt;

&lt;p&gt;Article 21. [Big disks belong to the company; good sleep belongs to you?] [WAAAGH! Reckon it'll work!]&lt;/p&gt;

&lt;p&gt;Well, it's finally written. The keyboard now belongs to you, Agent bros. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;run Tokens, run!!!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>rust</category>
      <category>filesystem</category>
      <category>ai</category>
    </item>
    <item>
      <title>SOP and Gate Design under Claude---Writing a COW Filesystem from Scratch, Part 3</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Sun, 04 Oct 2026 02:53:06 +0000</pubDate>
      <link>https://dev.to/faliye/sop-and-gate-design-under-claude-writing-a-cow-filesystem-from-scratch-part-4-3e40</link>
      <guid>https://dev.to/faliye/sop-and-gate-design-under-claude-writing-a-cow-filesystem-from-scratch-part-4-3e40</guid>
      <description>&lt;h3&gt;
  
  
  What is an SOP?
&lt;/h3&gt;

&lt;p&gt;SOP stands for Standard Operating Procedure. You split a process into a number of steps, and for each step you say what to do and how to verify it. The result is a set of concrete steps that can be repeated, checked and signed off.&lt;/p&gt;

&lt;p&gt;In my boss's words, it's a bowl of ramen: how many noodles, how much water, how much salt, how much scallion. I'm pretty sure he meant Japanese ramen. When I cook it, it's more like: some noodles, a little oil, a reasonable amount of water, scallions at will.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a gate?
&lt;/h3&gt;

&lt;p&gt;This one hardly needs explaining. When I was a kid, my family said be home before six. Of course I could choose to come home after eleven, but not coming home wasn't an option. The curfew was just there. It triggers when you walk in the door: men's singles, women's singles, or mixed doubles.&lt;/p&gt;




&lt;p&gt;End of the main text.&lt;/p&gt;




&lt;p&gt;My last article covered the three-way (Three-Body-style) adversarial setup for multiple agents, plus some code-style rules. But does three parties fighting it out solve the problem? Honestly, no.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/faliye/implementation-that-favors-the-ai-review-that-favors-the-human-writing-a-cow-filesystem-from-ng8" class="crayons-story__hidden-navigation-link"&gt;Implementation That Favors the AI, Review That Favors the Human---Writing a COW Filesystem from Scratch, Part 2&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/faliye" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" alt="faliye profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/faliye" class="crayons-story__secondary fw-medium m:hidden"&gt;
              faliye
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                faliye
                
                
              
              &lt;div id="story-author-preview-content-4794125" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/faliye" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;faliye&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/faliye/implementation-that-favors-the-ai-review-that-favors-the-human-writing-a-cow-filesystem-from-ng8" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/faliye/implementation-that-favors-the-ai-review-that-favors-the-human-writing-a-cow-filesystem-from-ng8" id="article-link-4794125"&gt;
          Implementation That Favors the AI, Review That Favors the Human---Writing a COW Filesystem from Scratch, Part 2
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/claude"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;claude&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rust"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rust&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/filesystem"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;filesystem&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/faliye/implementation-that-favors-the-ai-review-that-favors-the-human-writing-a-cow-filesystem-from-ng8#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            11 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;Agents write the docs, run the experiments and give the reports. Without limits, an agent will freely write all sorts of things, just like my ramen: somewhere between delicious and awful, at random.&lt;/p&gt;

&lt;p&gt;While working, I ran into a few fairly serious problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Even with prompt and skill constraints, agents often do things they were never authorized to do, or lose track because they forgot the context. How well it went, whether it's actually finished, all "more or less", just like my ramen. So quality depends entirely on how focused and responsible I am that day. My focus and sense of responsibility fluctuate, so of course the results differ between my highs and my lows.&lt;/li&gt;
&lt;li&gt;Agents like to overthink. They fall into endless thinking, trying to find the perfect answer, especially on open-ended questions with no clear goal, where they deliberate at length all the time. It's like Go: I may be the weaker player, but I can always use the wear-down-the-old-man tactic. Unfortunately, next to a silicon life form, I'm the old man. A forty-minute think I can sit through. Three forty-minute thinks in a row, I can't.&lt;/li&gt;
&lt;li&gt;Thanks to the breakneck progress of AI, a subagent can now send out minions of its own. The token explosion aside, the minions of the minions of the minions are a blind spot for me. I can go and read their thinking, but they're beyond what I can manage. My energy is limited, so I end up with minions of minions of minions who are not my minions.&lt;/li&gt;
&lt;li&gt;The main agent does the scheduling, and I'd rather not hand it the writing of code or docs. The sub-agents that fight each other haven't settled on a conclusion until they're done, so they certainly shouldn't write into the main directory. That means designing more subagents for the main agent to call: some write code, some review it. And the ones who write code and the ones who review it can't sit together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So there's nothing for it. To keep the project going, let's change a few things.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. SOP and separation of duties (for problem 4)
&lt;/h2&gt;

&lt;p&gt;Turn agent orchestration into a full pipeline: retrieval -&amp;gt; investigation -&amp;gt; implementation -&amp;gt; self-check -&amp;gt; knowledge rot -&amp;gt; gate.&lt;/p&gt;

&lt;p&gt;Each stage has one subagent definition under .claude/agents/. Every description says "use only when the main agent dispatches you by name... never auto-dispatch", and what material the role needs goes in required-inputs. Here they are, excerpted (the originals are written in Chinese; I've translated the descriptions):&lt;/p&gt;

&lt;p&gt;Retrieval: the retrieval agent may go online, carry material back and put it in the designated directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prior-art&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Researcher. Looks up other filesystems' source and docs on demand, hands back only facts with citations, no arguments. Use only when the main agent dispatches you by name with the question to look up; never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Bash, WebFetch, WebSearch&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;draft directory, report&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Investigation: the three-way adversarial setup kicks in to find a suitable approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;experiment-designer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Experiment designer. Takes an experiment number and writes the pre-run registration (arms, controls, criteria, failure clauses) before any code or artifact exists. Use only when the main agent dispatches you by name with the question to answer and the clause under test; never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opus&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;draft directory, clause under test, fork list|question list|rerun&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;three-way-attack&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The cloud attacker leg of the three-way argument. Use only when the main agent dispatches you by name with this round's background material, attack surface and the verdicts of earlier rounds; never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opus&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-read list, draft directory, background material, attack surface&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementation: start writing code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;implementation-writer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Implementer. Changes crates/ for one milestone step, one parallel line, or a cluster the main agent has bundled (may close several items), with tests, and proves the tests go red. Use only when the main agent dispatches you by name with the step number and the clauses in play; never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Edit, Write, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opus&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;draft directory, report, clause, crates files to touch&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tooling-writer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tooling implementer. Changes gate stages, hooks, research scripts and watchdogs, or changes agent definitions, shared constraints and project rules according to a verdict. Every change first builds an input that should go red. Use only when the main agent dispatches you by name with which item is being closed and the exit; never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Edit, Write, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;draft directory, report, exit, files to change&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Self-check: a three-way siege to review code quality.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;investigator&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Investigator. When a test or gate result differs from expectation, reproduces the symptom, bisects down to file and line, and hands back a minimal repro plus the condition that would refute it. If the dispatch says "fix it once found" and the clause spells out the fix, carries on, fixes it and proves it red; if the clause doesn't, stops and hands back to the main agent. Use only when the main agent dispatches you by name with the verbatim symptom and the question to answer; never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Edit, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opus&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;symptom, draft directory, report&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Knowledge rot: audit the whole project to check that every change is consistent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sweep&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sweeper. After a number is retracted, a format constant changes, a new criterion is established, or a stage of work ends, searches the whole repo for places that still cite the old value, should now be governed by the new criterion, or have been made &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="s"&gt; by this stage, and hands back a classified list. Use only when the main agent dispatches you by name with the old value and which quantity it is (or the stage's scope of change and what it achieved); never auto-dispatch.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;required-inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;draft directory, report&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gate: at the end of a task, mechanically check the error ledger, then the main agent analyzes and fixes the problems.&lt;/p&gt;

&lt;p&gt;Every node has its own specialist for its own job. The main agent only breaks down and dispatches tasks, and every subagent minds its own business. On top of that, there has to be a mechanism for "knowledge rot" that regularly clears out expired context, so the pipeline never runs overloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Limiting abilities (for problems 2 and 3)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Bash&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;omitClaudeMd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eliminate fuzziness and the gray zone. The main agent has to be clear what my task is, and then dispatch work to the subagents according to the task.&lt;/p&gt;

&lt;p&gt;Depth=1. A subagent may not have minions. That roots out the "blind spot" problem. (This corresponds to the environment variable CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1, and none of the roles has Agent in its tools anyway.)&lt;/p&gt;

&lt;p&gt;omitClaudeMd=true. It mustn't know too much. Context it doesn't need to know is withheld without exception, so it doesn't start free-associating.&lt;/p&gt;

&lt;p&gt;tools: tools are narrowed, strictly. Each role above gets a subset of Read, Edit, Write, Bash, WebFetch, WebSearch, and only the researcher can go online. Everyone has Bash, so the lock doesn't sit on tools; it sits on hooks: dangerous patterns are rejected before they execute, with no reliance on the agent's good manners.&lt;/p&gt;

&lt;p&gt;effort: high. Don't use more power than needed to solve a simple problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The gate (Harimoto siblings, go!) (for problems 1 and 2)
&lt;/h2&gt;

&lt;p&gt;Red-green dual proof: every piece of code must have a test. And a test that merely runs "green" (passes) isn't enough: you have to prove to me that the test can catch an error (red), and the red and green evidence must be submitted together. The red evidence doesn't rest on the agent's word either: the gate breaks the code under test in one spot and confirms that the test really goes red.&lt;/p&gt;

&lt;p&gt;Strong provenance: implementation must be tied to decision and experiment records. "Ghost code" with no historical decision behind it is not accepted, and the gate checks hard whether the comments explain where the code came from.&lt;/p&gt;

&lt;p&gt;Exhaustive probe points: plant lots of probes in the code, check the data state every time execution passes, weave a nerve net. For example, even if the code has run through two hundred thousand different points in a simulated environment, you still have to show that the data flow is complete and free of violations. Checks that aren't wired in yet are honestly marked unimplemented, and they're not allowed to pretend they passed.&lt;/p&gt;

&lt;p&gt;Text and format gate: check the knowledge base and docs item by item. Is everything written strictly in the preset JSON/Markdown format? Any ad-libbing? Does the record pass? Even a date has to be written as a standard date.&lt;/p&gt;

&lt;p&gt;Scheduled patrol (timeout mechanism): the main agent attaches a scheduled script that watches the subagents it has sent out at all times. If it sees the context grow too large or the runtime run over, it immediately checks task progress, and if things have drifted from expectation, pulls the agent back.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Dirty-write protection (for problem 4)
&lt;/h2&gt;

&lt;p&gt;Most mature agent frameworks are already aware of this one. For example, they use a worktree and the workspace under the root for physical isolation, so I don't have to build it from scratch.&lt;/p&gt;

&lt;p&gt;But I've added one extra lock: unless it has gone through the dedicated "implementation writer" agent node, no code is ever allowed to be written into crates.&lt;/p&gt;

&lt;p&gt;The one who writes code and the one who reviews it must be physically isolated. Without a double signature, you don't get past the main repo's threshold.&lt;/p&gt;

&lt;p&gt;With that, it should be able to run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tokenman&lt;/strong&gt;, move out!&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>rust</category>
      <category>filesystem</category>
    </item>
    <item>
      <title>Implementation That Favors the AI, Review That Favors the Human---Writing a COW Filesystem from Scratch, Part 2</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Sun, 04 Oct 2026 02:38:51 +0000</pubDate>
      <link>https://dev.to/faliye/implementation-that-favors-the-ai-review-that-favors-the-human-writing-a-cow-filesystem-from-ng8</link>
      <guid>https://dev.to/faliye/implementation-that-favors-the-ai-review-that-favors-the-human-writing-a-cow-filesystem-from-ng8</guid>
      <description>&lt;p&gt;In the last post, I decided to hand the keyboard over to the AI. But how to use the keyboard, what the key layout is, which input method to use: all of that is still unclear. To get a filesystem built sooner rather than later, I still need to make a little more effort.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/faliye/day1-choosing-to-be-wasteful-writing-a-cow-filesystem-from-scratch-part-1-4jg7" class="crayons-story__hidden-navigation-link"&gt;DAY1: Choosing to Be Wasteful---Writing a COW Filesystem from Scratch, Part 1&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/faliye" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" alt="faliye profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/faliye" class="crayons-story__secondary fw-medium m:hidden"&gt;
              faliye
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                faliye
                
                
              
              &lt;div id="story-author-preview-content-4794081" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/faliye" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160725%2Ffa9137c7-517b-4cce-824d-4317124139c7.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;faliye&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/faliye/day1-choosing-to-be-wasteful-writing-a-cow-filesystem-from-scratch-part-1-4jg7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/faliye/day1-choosing-to-be-wasteful-writing-a-cow-filesystem-from-scratch-part-1-4jg7" id="article-link-4794081"&gt;
          DAY1: Choosing to Be Wasteful---Writing a COW Filesystem from Scratch, Part 1
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/filesystem"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;filesystem&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rust"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rust&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/claude"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;claude&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/faliye/day1-choosing-to-be-wasteful-writing-a-cow-filesystem-from-scratch-part-1-4jg7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Part 1: Decisions and the Blueprint
&lt;/h2&gt;

&lt;p&gt;The implementer is an AI Agent. An Agent can write code toward a goal, but we lack a blueprint. A filesystem blueprint takes far more than five decisions. What goes into the self-contained unit (how many rooms)? How is the data format defined (how big is each room)? Are stripes variable (can the partitions be moved)? How is the journal handled (do we install a gate)? What is the first goal (fix the foundation first, or the roof)? All of these need decisions. Otherwise you may end up with the roof finished and the foundation not yet dug. We all know that Agents are superb executors when the goal is clear, but they are a bit weaker at planning complex tasks, and without a blueprint a task easily goes off track.&lt;/p&gt;

&lt;p&gt;But filesystem design is extremely complex and involves a mountain of prerequisite knowledge. Even if I started searching through references day and night without sleep, I might have a first design drawing five years from now. Fortunately, the Agent bro sitting next to me is exceptionally learned, so I can ask him to make the design decisions and draw the blueprint. His weakness is that he is prone to going off the deep end: overconfident, charging down one path to the bitter end. So I have to guard against an awkward situation: he may not be trying to deceive me (he is simply hallucinating), yet I have no way to tell whether the information he gives me is true or false. What to do?&lt;br&gt;
As the saying goes, three monks have no water to drink. Well then, let's get three Agent bros to work together anyway. Here is the design:&lt;/p&gt;

&lt;p&gt;The conversation where the task starts is called the Main Agent. It only asks questions according to the plan. For example, according to the plan, today we should decide how many rooms to design.&lt;/p&gt;

&lt;p&gt;This question is handed to one strong Agent (Strong A), who is responsible for collecting information and finding an answer that looks correct. Once he brings back this seemingly correct answer, the Main Agent notifies two more Agents, B the supporter and C the attacker, to start work.&lt;/p&gt;

&lt;p&gt;Supporter B looks for non-overlapping supporting evidence for the answer, that is, other arguments that also support it. If he finds any, he reports them; otherwise he reports that he could not find any.&lt;/p&gt;

&lt;p&gt;Opponent C looks for arguments that show the answer does not hold at all. If he finds any, he reports them; otherwise he reports that he found none. But the opponent must find strong evidence; weak evidence is treated as failing to find any.&lt;/p&gt;

&lt;p&gt;After collecting these reports, the Main Agent begins independent verification. The Main Agent does not judge who has the better argument; it judges and checks whether the results are valid. If they are valid, the Main Agent summarizes these points and has Strong A repeat the steps above and reason through a second round. Note that in the second round the Main Agent's materials have grown, now including both supporting and opposing views.&lt;/p&gt;

&lt;p&gt;At the same time, four points need attention:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An Agent's conclusions are random in nature. So before Strong A starts work, he must set a target for himself. If the conclusion drifts away from that target, the conclusion is invalid. For example, suppose we want to build three rooms and the conclusion is that flooring is better. That conclusion cannot be accepted. The file header comment of an Agent's experiment program contains the following: the criterion (written in stone before the run, not to be changed after it), the failure clause (written in stone before the run), the reverse-acceptance clause, and the questions it cannot answer.&lt;/li&gt;
&lt;li&gt;Agents have a natural tendency to agree with the user, and this must be eliminated completely. Even if a proposal comes from the user, the decision must still go through the three-party process; if it does not, it is not recognized as approved. The user can demand that it pass, but the AI will, at lightspeed, leave the evidence in a warning and then submit.&lt;/li&gt;
&lt;li&gt;Agents from the same source tend to think alike. Although we bring in two AIs to participate, to avoid this tendency I also brought in a local model to join the thinking and the attacking. A local model is usually useless, but every now and then it has a flash of inspiration.&lt;/li&gt;
&lt;li&gt;The Main Agent's data sources are not trustworthy. Each Agent must measure the data independently. This prevents the Main Agent from hallucinating some data into the context and thereby biasing the other Agents' judgment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, considering that AIs often have no stopping condition, if three rounds of three-party confrontation produce no result, reasoning stops and the question is summarized and handed to me to decide.&lt;/p&gt;

&lt;p&gt;With this process, my job becomes much simpler. I generally no longer need to re-check whether the materials are real. My attention is not spent on reading materials and checking for hallucinations; I spend it only on four things a machine cannot judge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this test measuring the right thing?&lt;/li&gt;
&lt;li&gt;Is this invariant itself correct?&lt;/li&gt;
&lt;li&gt;Does the basis of this decision hold up?&lt;/li&gt;
&lt;li&gt;Do I accept this trade-off?
This is the second half of our first heading: review that favors the human. Make sure the evidence is sufficient and the reasoning is valid, and let the human make the call.
And the cost? What's your superpower, Tokenman?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Part 2: Implementation and Code
&lt;/h2&gt;

&lt;p&gt;Before discussing this topic, two observations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If, in this era, AI context has reached the million-token scale, the context window can even hold all the code and documentation of a medium-sized project at once.&lt;/li&gt;
&lt;li&gt;The best practices of the past had human programmers as their subject.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Based on the second point, let's re-examine past best practices: function names should be short, for loop nesting should be shallow, functions should be reusable and abstracted and encapsulated, and so on. These practices actually address the problem of limited human brain bandwidth: short function names, shallow for nesting, and reuse, abstraction and encapsulation are all meant to reduce the load on the human brain. Today, for those of us programming toward Markdown (prompts), does the length of a variable name matter to us? Does shallow for nesting matter to us? Do reuse, abstraction and encapsulation matter to us?&lt;/p&gt;

&lt;p&gt;But note that these matter a great deal to the Agent.&lt;/p&gt;

&lt;p&gt;When an Agent modifies a function, it greps, and function names and variable names are always the first coordinates. If a name alone can tell you what something is and what it does, that lowers the Agent's hallucination rate, because comments may be forgotten, but the name anchor gets used again and again.&lt;/p&gt;

&lt;p&gt;Ten levels of for loops with no if inside are just a traversal to an Agent. An exhaustive match with 12 arms is counted for you by the compiler; 12 independent layers of if/else are 2^12 paths, which you cannot finish testing.&lt;/p&gt;

&lt;p&gt;Abstraction and encapsulation are the biggest source of bugs in code. Their main benefit is making code easier for humans to maintain, but for an AI, modifying one place costs about the same as modifying ten.&lt;/p&gt;

&lt;p&gt;Today the main force writing and reading code is the model. Sorting out logic, maintaining consistency and exhaustive coverage are exactly what machines are good at. A floor set by the limits of the human brain is far too low for a machine.&lt;/p&gt;

&lt;p&gt;So our default attitude toward "best practices" is skepticism, not compliance. This does not mean they are all wrong; it means the reason behind each one has to be re-examined.&lt;/p&gt;

&lt;p&gt;Four steps to audit an old rule:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What problem was it originally meant to solve? If you can't say, drop it immediately.&lt;/li&gt;
&lt;li&gt;Does that problem still exist today? If it was solving "humans can't remember," "humans can't read it all," or "reviewers are too busy," it most likely no longer exists.&lt;/li&gt;
&lt;li&gt;Does it have a second reason, one that has nothing to do with humans? If so, keep it, and rewrite the reason to be that one.&lt;/li&gt;
&lt;li&gt;Can the rewritten reason be turned into a gate? If it can't, downgrade it 
to a suggestion.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is only one criterion: does this rule make the code easier to verify mechanically, or does it only make the code easier for human eyes to skim? Keep the former; the latter can be dropped.&lt;br&gt;
Here is a brief summary of some past best practices.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Popular practice&lt;/th&gt;
&lt;th&gt;Disposition&lt;/th&gt;
&lt;th&gt;How we write it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Names should be short, and the closer to the declaration the shorter&lt;/td&gt;
&lt;td&gt;Abolished&lt;/td&gt;
&lt;td&gt;No length limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop counter called i, temporary variable called tmp&lt;/td&gt;
&lt;td&gt;Abolished&lt;/td&gt;
&lt;td&gt;Name it for what it is: stripe_index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Functions under 20 lines&lt;/td&gt;
&lt;td&gt;Kept, reason rewritten&lt;/td&gt;
&lt;td&gt;Cut by "one thing that can be verified on its own," not by line count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nesting no deeper than three levels&lt;/td&gt;
&lt;td&gt;Relaxed&lt;/td&gt;
&lt;td&gt;No limit on depth; what is limited is the number of paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single exit&lt;/td&gt;
&lt;td&gt;Abolished&lt;/td&gt;
&lt;td&gt;Early returns freely allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace conditional branches with polymorphism&lt;/td&gt;
&lt;td&gt;Abolished for closed sets&lt;/td&gt;
&lt;td&gt;enum plus exhaustive match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DRY, avoid repetition&lt;/td&gt;
&lt;td&gt;Relaxed&lt;/td&gt;
&lt;td&gt;Repetition must be generated, never copied by hand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;default: fallback is safer&lt;/td&gt;
&lt;td&gt;Abolished for closed sets&lt;/td&gt;
&lt;td&gt;Leave missed cases for the compiler to catch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One assertion per test&lt;/td&gt;
&lt;td&gt;Abolished&lt;/td&gt;
&lt;td&gt;One scenario per test; multiple assertions allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No more than 80 columns per line&lt;/td&gt;
&lt;td&gt;Left to tools&lt;/td&gt;
&lt;td&gt;rustfmt decides; don't shorten names for line width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avoid premature optimization&lt;/td&gt;
&lt;td&gt;Downgraded to a suggestion&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Part 3: Practice in Rust
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. No abbreviations, except those registered in the abbreviation table
&lt;/h3&gt;

&lt;p&gt;Without reading comments, without looking at call sites, without looking at the implementation, from the name alone you should be able to say what it is, what it does, and what it does not do.&lt;/p&gt;

&lt;p&gt;No abbreviations: write cnt, idx, buf, tmp out in full. Domain abbreviations (lba, crc) may be used only once registered, and the registry is their sole authoritative definition.&lt;/p&gt;

&lt;p&gt;No single letters: write i as stripe_index, the generic parameter T as Key, the lifetime 'a as 'journal, and Err(e) as Err(error).&lt;/p&gt;

&lt;p&gt;Write preconditions into the name: write_node says nothing; append_verified_node_to_journal says three things: it appends rather than overwrites, the input has been verified, and it lands in the journal region.&lt;/p&gt;

&lt;p&gt;Test names state the scenario and the expectation: crash_between_data_write_and_commit_keeps_previous_generation, not test_commit.&lt;/p&gt;

&lt;p&gt;One concept, one name across the whole repository: it must not be called generation here and epoch there.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Semantics go in types first: types &amp;gt; names &amp;gt; comments
&lt;/h3&gt;

&lt;p&gt;Take the following example. The same thing written three ways; when the semantics live in the type, an AI that writes it wrong gets an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Semantics in comments: the worst&lt;/span&gt;
&lt;span class="c1"&gt;// dim0: nationality  dim1: gender  dim2: age band&lt;/span&gt;
&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Semantics in names: criticized as verbose in the past, machines love it&lt;/span&gt;
&lt;span class="n"&gt;number_of_people_in_japan&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;foreigner&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;woman&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;teenager_18_to_24&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Semantics in types: the best, a wrong dimension simply won't compile&lt;/span&gt;
&lt;span class="n"&gt;number_of_people_in_japan&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nn"&gt;Nationality&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;USA&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nn"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Woman&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nn"&gt;AgeBand&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Teenager18To24&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Branching: write every case out, never write _ =&amp;gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Medium&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Rotational&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SolidState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Zoned&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;zone_size_in_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;node_size_in_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Medium&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;medium&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// the point is that there is no `_ =&amp;gt;` wildcard arm&lt;/span&gt;
        &lt;span class="nn"&gt;Medium&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Rotational&lt;/span&gt;                   &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Medium&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SolidState&lt;/span&gt;                   &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Medium&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zoned&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;zone_size_in_bytes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;zone_size_in_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is the _ =&amp;gt; that was not written. Add it and the code looks shorter and more "general," but it switches off exactly the compiler's exhaustiveness check. Later, when a new kind of medium is added, the program will quietly walk into the wildcard arm; the behavior will be wrong and nobody will raise an alarm.&lt;/p&gt;

&lt;p&gt;The criterion is not "how many branches there are" but "if a case is missed, who finds out first": the compiler, or production.&lt;/p&gt;

&lt;p&gt;A few related practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For encodings read from disk that may gain new values later, make - "unknown" an explicit member (Unrecognized(raw_code)), and match remains exhaustive.&lt;/li&gt;
&lt;li&gt;Use enum for closed sets, not trait objects. A trait's default method is in fact also a kind of wildcard arm.&lt;/li&gt;
&lt;li&gt;Don't abstract a trait with only one implementation. Don't abstract "to make swapping easier later."&lt;/li&gt;
&lt;li&gt;For interactions between two cases, write an exhaustive match on a tuple.
In singlefs's code we enforce the following:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map_scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map_scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LogicalIdentityWriteOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AllPointers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LogicalIdentityWriteOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Code1Only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MixedPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="nn"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AllPointers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MixedPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="nn"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Code1Only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ClassReuseTagged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="nn"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AllPointers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ClassReuseTagged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="nn"&gt;MapScope&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Code1Only&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Geometry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two of the rows actually have identical values, and most people would merge them. Here we do not merge them: the day a fourth candidate is added, the code will not compile until this spot is updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Types: make illegal states unwritable
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq)]&lt;/span&gt; &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;LogicalAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq)]&lt;/span&gt; &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;PhysicalAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PhysicalAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// read_block(LogicalAddress(value)) simply won't compile&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;RawNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// just read from disk, unverified&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;VerifiedNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// checksum compared and passed&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;RawNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected_checksum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Checksum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VerifiedNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CorruptBlock&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;VerifiedNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;// want to skip verification? the argument can't even be constructed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first snippet turns "passing the wrong address" from a runtime bug into a compile-time error. The second is even harsher: it makes "not yet verified" a type too, so "forgetting to verify" simply cannot be written. Verify once at the boundary, then trust the types inside, instead of re-checking at every layer.&lt;/p&gt;

&lt;p&gt;A few smaller points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace boolean parameters with enums. write(node, true) says nothing at the call site; write(node, Durability::Synced) does.&lt;/li&gt;
&lt;li&gt;When constructing a struct, write out every field; don't use ..Default::default(). It is a wildcard arm over fields: add a new field, and every place that didn't write it quietly gets the default value.&lt;/li&gt;
&lt;li&gt;Don't use as for lossy numeric conversions; use try_from and handle the failure. as truncates, drops signs and wraps around, all without any error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Branching and types are in fact two sides of the same thing: one lets the compiler catch "a missed case," the other makes "an illegal combination" unwritable. Both move the checking from humans to machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Errors: recoverable ones go into types, invariant violations get assertions
&lt;/h3&gt;

&lt;p&gt;I/O errors, on-disk data corruption and running out of space are recoverable, and go through Result. The error enum is divided by the decision the caller must make (not found, data corrupt, out of space, other I/O error), not expanded one by one by underlying cause.&lt;/p&gt;

&lt;p&gt;At the public boundary of a library, don't use a unified error type like anyhow. It lumps "retry, report corruption, report out of space" into one blob, and is a wildcard arm on errors.&lt;/p&gt;

&lt;p&gt;A broken invariant is a bug: assert immediately, don't carry bad state forward, and above all don't write it to disk.&lt;/p&gt;

&lt;p&gt;Don't write unwrap(); write expect, with a message stating which invariant it relies on.&lt;/p&gt;

&lt;p&gt;An expect in experimental code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"leaf number is not in the position table: the position table did not keep up after the split"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distinct_groups&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"the number of distinct nodes fits in u64"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each expect is a named assertion. The day it blows up, the message says directly which assumption collapsed.&lt;/p&gt;

&lt;p&gt;Longer names, more types, more complete branches. The compiler reports a few more errors. That is what being AI-friendly means on the implementation side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally: What We Lost, and What We Gained
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Wasted tokens.&lt;/strong&gt; One question, three legs, three rounds, sometimes eight; one set of background material runs over two thousand lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wasted time.&lt;/strong&gt;The format design took a full three weeks, and not a single line of the filesystem itself has been written.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wasted code.&lt;/strong&gt; The experimental code may be very long, yet not a single line of implementation code has been written.&lt;/p&gt;

&lt;p&gt;Wasted characters. Names written in full, branches written in full, every rejection accompanied by a next step.&lt;/p&gt;

&lt;p&gt;What we gained:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A conclusion that has not been verified will never appear in the code.&lt;/li&gt;
&lt;li&gt;The code may still be wrong, but when it is wrong, it will be caught.&lt;/li&gt;
&lt;li&gt;What I decide is on the record, and when I say something wrong, someone comes to strike it down.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It doesn't matter that I don't have the knowledge: the Agents come to me with evidence and options, and multiple choice is something I can do. Reviewing makes me happy.&lt;/p&gt;

&lt;p&gt;I don't write the code, but when it is written wrong, it fails loudly at any time. Simple, linear, multi-branch code should be fun for an Agent to write, I imagine.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>rust</category>
      <category>filesystem</category>
      <category>ai</category>
    </item>
    <item>
      <title>DAY1: Choosing to Be Wasteful---Writing a COW Filesystem from Scratch, Part 1</title>
      <dc:creator>faliye</dc:creator>
      <pubDate>Sun, 04 Oct 2026 02:07:33 +0000</pubDate>
      <link>https://dev.to/faliye/day1-choosing-to-be-wasteful-writing-a-cow-filesystem-from-scratch-part-1-4jg7</link>
      <guid>https://dev.to/faliye/day1-choosing-to-be-wasteful-writing-a-cow-filesystem-from-scratch-part-1-4jg7</guid>
      <description>&lt;p&gt;I'm going to build a filesystem. The way I'm going about it might not be entirely proper. Still, I figured I should write something down, though I suspect this series won't have much actual technical content.&lt;/p&gt;

&lt;p&gt;To open the series, allow me to explain the basic concepts of filesystems with my very limited knowledge.&lt;/p&gt;

&lt;p&gt;A filesystem is the set of data structures and directory rules an operating system uses to organize, manage and retrieve data on disk. Whether or not you use a computer, you can't escape this storage system.&lt;/p&gt;

&lt;p&gt;Traditional filesystems (like Ext4 and XFS) are update-in-place. The data unit (the block) has a fixed size, and changing one goes read → modify → write, back to the same spot. It's stable and solid, but since it's an overwrite, once you write, the old data is gone. Ext4 and XFS use a journal to protect metadata, so recovery after a power cut is fast. But the journal doesn't protect the data itself. And snapshots and rollback are hard to build in the filesystem alone, so you end up relying on something below it, like LVM, or on a separate backup system.&lt;/p&gt;

&lt;p&gt;So if the traditional approach needs all this extra machinery, why not just put those features inside the filesystem? Don't overwrite data. Write it somewhere new, then point the pointer that used to reference the old data at the new data instead. When new data is written the old data isn't overwritten, and as long as some snapshot still references it, the old data stays. Snapshots come almost for free. Since old data doesn't vanish right away, rollback is easy too. By the same logic, if the power dies suddenly, as long as that final "pointer switch" hasn't completed, the disk still holds a complete old version. No long repair needed, and crash consistency is naturally stronger.&lt;/p&gt;

&lt;p&gt;This is the COW (copy-on-write) filesystem, with Btrfs and ZFS as the famous examples. Of course, there's no free lunch. COW pays for it with write amplification, fragmentation, and the job of reclaiming space once nobody references the old data anymore.&lt;/p&gt;




&lt;p&gt;That's the end of the main text. Everything below is not the main text.&lt;/p&gt;




&lt;h2&gt;
  
  
  So, why write a new COW filesystem?
&lt;/h2&gt;

&lt;p&gt;One day in mid-August, while reading up on filesystems, two questions suddenly popped into my head:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why is the unit size of filesystems almost always 4K?&lt;/li&gt;
&lt;li&gt;Why do most systems go to such lengths to keep their data structures compact?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My answers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, 4K is the memory page size. The page cache and memory mapping are all page-aligned, so making the block the same size as a page is simply the easiest thing to do. It's also the physical sector size after disks moved from 512-byte to 4K sectors (Advanced Format). The bigger the block, the more space small files waste (internal fragmentation), so nobody dared make it larger.&lt;/li&gt;
&lt;li&gt;Ten or twenty-odd years ago, storage was outrageously expensive. Every filesystem was desperately trimming itself down, saving as much disk space as possible for actual data, and leaving the organizing of structures to complicated, clever algorithms.
It reminds me of a joke. The diameter of a rocket, the crystallization of human technology, is supposedly limited by the width of railway tracks, because of transport constraints. The track width came from the English, who set it to the width of two horses' backsides, because trains were originally pulled by horses. (It's a popular story, but whether it's true is doubtful. Take it as a joke.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Looking at computers today, storage has become cheap and huge, even if prices have crept up a bit lately. An SSD has no head and no spinning platter. Data lives in NAND flash, is read and written in pages (roughly 16KiB), and inside there are multiple channels and dies working in parallel. So a big chunk of data can be pulled out at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  So maybe a design like this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A data unit carries, besides its data, a description of who it is and what it belongs to. It holds the information it needs about itself (self-contained). Even if it sits in some far corner of the disk, a scan is enough to find its owner.&lt;/li&gt;
&lt;li&gt;Since a unit can explain its own origin, the tree that used to describe it loses its main job. The tree becomes just an index for fast access to units. It has no other duties and doesn't carry small data. So it can be thrown away and rebuilt.&lt;/li&gt;
&lt;li&gt;For future compatibility, leave some bytes empty as extension points. That doesn't save space. It actively wastes it.&lt;/li&gt;
&lt;li&gt;Since we're choosing the future, old spinning hard disks stop being an optimization target. We aim entirely at new SSDs, newer FTLs and ZNS (Zoned Namespaces). That said, the SSD's own garbage collection and the filesystem's space reclamation are two different layers. The former handles erasing flash blocks. The latter handles which old versions nobody references anymore. We still have to do the latter ourselves, though it can cooperate with TRIM and ZNS.&lt;/li&gt;
&lt;li&gt;Since SSDs are the target, we align data to the SSD's pages and parallel stripes. Metadata is 16KiB and data is 32KiB, so one read can take in a whole stripe.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Problems still to solve
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;How to implement it: who's going to build this?&lt;/li&gt;
&lt;li&gt;Which language: how do we make it easy to verify?&lt;/li&gt;
&lt;li&gt;Code style: how do we keep it simple and clear?&lt;/li&gt;
&lt;li&gt;What to verify with: how do we tell right from wrong?
Scratches head. Fine, let's just do this.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Choosing how to implement it
&lt;/h3&gt;

&lt;p&gt;I know very little about filesystems and definitely can't write a line of it. Writing this myself isn't realistic.&lt;/p&gt;

&lt;p&gt;The keyboard goes to the AI. Tokens aren't that expensive right now, so let's be a little wasteful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the language
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;It must compile to something fast enough.&lt;/li&gt;
&lt;li&gt;It must have strong verification.
Content goes to Rust. Write more verification. Let's be a little wasteful.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Choosing the code style
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Absolutely few branches. Too many if-else and the combinations to verify grow exponentially. AI makes mistakes easily.&lt;/li&gt;
&lt;li&gt;Abstract as little as possible. Don't reuse a function if you can avoid it. Copy-paste if you can. Never couple things together or mix them up.&lt;/li&gt;
&lt;li&gt;Variable names must be long. Seeing a name should tell you the function's past and present life.
A bit bloated is fine. Write more code, write it longer. Let's be a little wasteful.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Choosing how to verify
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;I don't understand code, so every plan must be put to a vote by several parties. Three AIs debate for three rounds, and I'm the referee.&lt;/li&gt;
&lt;li&gt;I can't tell right from wrong, so let's just simulate-verify every single point. As for power loss, QEMU, that's yours: cut at every possible crash point, replay, and see whether the filesystem still recognizes itself.&lt;/li&gt;
&lt;li&gt;I don't understand timing, so let's enumerate every reordering of concurrent operations. herd7, you're up: given a memory model, it lists every outcome that's allowed to happen. Order out of chaos.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;** Not understanding is fine. Verify more. Let's be a little wasteful. **&lt;/p&gt;

&lt;p&gt;And with that, our core decisions are done.&lt;/p&gt;

&lt;p&gt;Day 1, and the most critical decisions are made.&lt;/p&gt;

&lt;p&gt;Looking back, I reckon it's not bad. WAAAGH!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>filesystem</category>
      <category>rust</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
