<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://superposition.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://superposition.github.io/" rel="alternate" type="text/html" /><updated>2026-09-11T17:48:23-04:00</updated><id>https://superposition.github.io/feed.xml</id><title type="html">Superposition</title><subtitle>Thinking above the code. Notes on AI, mathematics, kernels, and the directions they open.</subtitle><author><name>Superposition</name></author><entry><title type="html">The 4090 and the Nano</title><link href="https://superposition.github.io/journal/the-4090-and-the-nano/" rel="alternate" type="text/html" title="The 4090 and the Nano" /><published>2026-09-11T17:05:00-04:00</published><updated>2026-09-11T17:05:00-04:00</updated><id>https://superposition.github.io/journal/the-4090-and-the-nano</id><content type="html" xml:base="https://superposition.github.io/journal/the-4090-and-the-nano/"><![CDATA[<p><strong>The claim.</strong> The verification story so far is kernel-level, on both machines, and the gap between
them is measured. The same <strong>13 CUDA launches over 5 kernels</strong> cost <strong>4.78 ms</strong> of kernel time on the
RTX 4090 (<code class="language-plaintext highlighter-rouge">docs/evidence/baseline-2026-09-11/</code>, commit <code class="language-plaintext highlighter-rouge">76143f0</code>) and <strong>39.18 ms</strong> on the Orin NX
(<code class="language-plaintext highlighter-rouge">docs/evidence/T50/pinkie-kernels/</code>, <code class="language-plaintext highlighter-rouge">a28736f</code>) — <strong>8.19× slower</strong>. Two kernels are 99.6 % of it:
<code class="language-plaintext highlighter-rouge">belief_update</code> <strong>12.976 ms</strong> and <code class="language-plaintext highlighter-rouge">cognition_update</code> <strong>12.991 + 13.046 ms</strong>, both one block of 1024
threads where each thread walks a full 1024-wide row in a serial loop. The counters separate two
questions: how many warps are resident on the SM at once (occupancy), and how much work each resident
warp issues per cycle (throughput). <code class="language-plaintext highlighter-rouge">belief_update</code> has <strong>65.59 %</strong> of peak sustained-active warps —
almost the same as <code class="language-plaintext highlighter-rouge">costmap_stats</code>’ <strong>64.58 %</strong> — but issues work at <strong>1.52 %</strong> of peak SM throughput
against <code class="language-plaintext highlighter-rouge">costmap_stats</code>’ <strong>16.58 %</strong>. An <strong>11×</strong> difference in issued work per cycle at equal
residency is a loop problem, not an occupancy problem. And the deploy side has its own first result: the stack went
to the board at <code class="language-plaintext highlighter-rouge">25f2b6f7</code> and the probe <strong>hung</strong> — a plain-HTTP Leash on :8000 and a stack whose only
default address was <code class="language-plaintext highlighter-rouge">https://127.0.0.1:8080</code>, llama.cpp’s plain-HTTP port.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-4090-and-the-nano/kernel-durations.svg" width="1100" height="449" alt="Two panels. Left: each of the five kernels' mean time per launch on the RTX 4090 and on the Orin NX, log axis, with its launch count — the same 13 launches summing to 4,784.753 and 39,182.176 microseconds (8.19x). Right: the board's residency against its issued work per cycle, with belief_update and costmap_stats at 65.59% and 64.58% of peak sustained-active warps but 1.52% and 16.58% of peak SM throughput." />
  </picture>
  <figcaption>
    <p>The same 13 launches on two machines: left, each kernel's mean time per launch on the RTX 4090
    and the Orin NX (log axis), with its launch count, summing to 4,784.753 µs and 39,182.176 µs
    (8.19×); right, the board's residency against its issued work per cycle —
    <code>belief_update</code> and <code>costmap_stats</code> at 65.59 % and 64.58 % of peak
    sustained-active warps but 1.52 % and 16.58 % of peak SM throughput.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>The mission tickets’ runs are not what this entry measures.</strong> Step 28 (an end-to-end mission on the
4090) is <a href="https://github.com/superposition/qualia/issues/44">T28 (#44)</a> and
Step 29 (the same on the Orin Nano) is <a href="https://github.com/superposition/qualia/issues/45">T29 (#45)</a>.
When this entry landed on 2026-09-11T19:24Z, T28 had no comments at all and T29’s only comment was a
blocked deploy smoke, not a mission; no mission had run on either machine. T28 has since run its host
mission — <code class="language-plaintext highlighter-rouge">open_missions</code> 0 → 1 → 0, a sealed 2395-byte MCAP and the mission id in the session list,
on a zero-motion stack (<code class="language-plaintext highlighter-rouge">docs/evidence/T28/4090-mission/</code> on <code class="language-plaintext highlighter-rouge">ticket/T28</code>, <code class="language-plaintext highlighter-rouge">449eeea</code>). As of
2026-09-11T20:45Z, PR #213 was open with <code class="language-plaintext highlighter-rouge">#44</code> <code class="language-plaintext highlighter-rouge">status:review</code>, T29’s board half had not run (<code class="language-plaintext highlighter-rouge">#45</code>
<code class="language-plaintext highlighter-rouge">status:review</code>, PR #211), and neither ticket was <code class="language-plaintext highlighter-rouge">status:done</code>. What this entry’s numbers measure is
the kernel suite, on both machines.</p>

<p><strong>The board deploy was attempted early, on purpose, and recorded as blocked.</strong> Deploying <code class="language-plaintext highlighter-rouge">25f2b6f7</code>
to <code class="language-plaintext highlighter-rouge">~/qualia-deploy/</code> and building natively on the board was cheap and proved the deploy path; the
run path then exposed, in order, that the toolchain is not on <code class="language-plaintext highlighter-rouge">PATH</code> for non-interactive SSH, that
<code class="language-plaintext highlighter-rouge">cargo</code> resolves every workspace member even for one <code class="language-plaintext highlighter-rouge">-p</code> (so one uncached dev-dependency of an
unrelated crate kills a single-package build), that the board’s registry cache is both partial and
<em>older</em> than <code class="language-plaintext highlighter-rouge">main</code>’s lock, and that the board has no DNS, so <code class="language-plaintext highlighter-rouge">git clone</code> and crates.io are both
unreachable and the only path is stage-and-ship. The recipe that works — <code class="language-plaintext highlighter-rouge">git archive</code>, <code class="language-plaintext highlighter-rouge">scp</code>, a
trimmed <code class="language-plaintext highlighter-rouge">members</code> list, <code class="language-plaintext highlighter-rouge">cargo generate-lockfile --offline</code> — is written into the comment and into
D-016/D-018.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-4090-and-the-nano/deploy-path.svg" width="1100" height="830" alt="The stage-and-ship path drawn as stages with each obstacle noted beside the stage it stopped: git archive on the host, scp to jetson@192.168.55.1, unpack with the workspace trimmed, native --release --offline build, the PTX ceiling (driver 540.4 JITs 8.5 and below, NVRTC 12.9 emits 8.8), the compat-loader fix, 5 passed, and the two ncu runs." />
  </picture>
  <figcaption>
    <p>The stage-and-ship path: <code>git archive</code> on the host → <code>scp</code> to
    <code>jetson@192.168.55.1</code> → unpack with the workspace trimmed → native
    <code>--release --offline</code> build → the PTX ceiling (driver 540.4 JITs ≤ 8.5, NVRTC 12.9
    emits 8.8) and the compat-loader fix → 5 passed and the two <code>ncu</code> runs, each obstacle
    as a note beside the stage it stopped.</p>
  </figcaption>
</figure>

<p><strong>Two obstacles were specific to the board’s driver.</strong> NVRTC 12.9 emits PTX ISA 8.8; the board’s
driver 540.4 JITs 8.5 and below, so every device test skipped itself with
<code class="language-plaintext highlighter-rouge">CUDA_ERROR_UNSUPPORTED_PTX_VERSION</code>. A direct driver probe found the ceiling (<code class="language-plaintext highlighter-rouge">load ptx-8.5 result=0</code>
/ <code class="language-plaintext highlighter-rouge">ptx-8.6 result=222</code>) and the fix: the toolkit’s forward-compatibility <code class="language-plaintext highlighter-rouge">libcuda</code>, reached with
<code class="language-plaintext highlighter-rouge">LD_LIBRARY_PATH=/usr/local/cuda-12.9/compat</code>. A cubin built by the board’s own <code class="language-plaintext highlighter-rouge">nvcc -arch=sm_87
-cubin</code> also loads on the stock driver and is the named fallback; the compat loader was used because
it changes neither the kernels nor the driver. Also stated, not hidden: the Tegra driver exposes no
DRAM counter, so <code class="language-plaintext highlighter-rouge">dram__bytes.sum</code> is <code class="language-plaintext highlighter-rouge">n/a</code> and no memory-bound verdict is claimed.</p>

<h2 id="the-same-launches-two-machines">The same launches, two machines</h2>

<p>The ranking reproduces; the durations do not. On the 4090 the same file cost 4784.75 µs with the same
13 launches and shapes. On the board it cost 39,182.18 µs with the GPC clock held near <strong>306 MHz</strong>,
which is the board’s <strong>10 W</strong> power mode, not a profiler artefact: the unlocked repeat reports the
same total to <strong>0.001 %</strong> (39 182 176 vs 39 181 760 ns) and <code class="language-plaintext highlighter-rouge">belief_update</code> to 0.14 %. The board has
<strong>4 SMs</strong> in 2 TPCs, and the 1 × 1024 kernels launch one block in total — <code class="language-plaintext highlighter-rouge">waves_per_sm</code> 0.25 is that
one block averaged over four SMs, and register pressure caps it at one block per SM (theoretical
occupancy 66.67 %: 1024 of the 1536 threads the SM can hold). The 4090’s cycle count for the same
kernel is an <strong>inference</strong>, not a measurement — the capture did not measure that clock — but the shape
is what a latency-bound kernel predicts: the same cycles, a slower clock, a proportionally larger wall
time, and the naive shape is worst exactly where it ships.</p>

<figure class="measurement">
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.5.0/model-viewer.min.js"></script>
  <model-viewer src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-4090-and-the-nano/turntable.glb" camera-controls="" auto-rotate="" disable-zoom=""></model-viewer>
  <figcaption>
    <p>The extruded mark plus one pillar per kernel in the board's capture, each pillar's height its
    mean time on the Orin NX — two pillars and three stubs, the 99.6 % the entry states — with a
    60-frame rotation baked as an animation. If the viewer script does not load, the same
    <a href="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-4090-and-the-nano/turntable.glb">GLB
    downloads from the same figure</a>.</p>
  </figcaption>
</figure>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>4090 kernel suite (baseline)</td>
      <td style="text-align: right">4784.75</td>
      <td>µs</td>
      <td><code class="language-plaintext highlighter-rouge">baseline-2026-09-11/README.md</code> ^1</td>
    </tr>
    <tr>
      <td>Orin NX kernel suite</td>
      <td style="text-align: right">39,182,176 (39.18 ms)</td>
      <td>ns</td>
      <td><code class="language-plaintext highlighter-rouge">T50/pinkie-kernels/README.md</code> ^2</td>
    </tr>
    <tr>
      <td>Board / 4090 ratio</td>
      <td style="text-align: right">8.19×</td>
      <td>—</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">belief_update</code> on board</td>
      <td style="text-align: right">12,976,128</td>
      <td>ns</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">cognition_update</code> on board</td>
      <td style="text-align: right">13,046,368 / 12,991,136</td>
      <td>ns</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Warps active, <code class="language-plaintext highlighter-rouge">belief_update</code></td>
      <td style="text-align: right">65.59</td>
      <td>% of peak</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>SM throughput, <code class="language-plaintext highlighter-rouge">belief_update</code></td>
      <td style="text-align: right">1.52</td>
      <td>% of peak</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>SM throughput, <code class="language-plaintext highlighter-rouge">costmap_stats</code></td>
      <td style="text-align: right">16.58</td>
      <td>% of peak</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Launches / kernels (both)</td>
      <td style="text-align: right">13 / 5</td>
      <td>—</td>
      <td>both captures</td>
    </tr>
    <tr>
      <td>Board SMs / TPCs</td>
      <td style="text-align: right">4 / 2</td>
      <td>—</td>
      <td><code class="language-plaintext highlighter-rouge">kernels.csv</code></td>
    </tr>
    <tr>
      <td>Board GPC clock</td>
      <td style="text-align: right">~306</td>
      <td>MHz</td>
      <td>T50 README (exploratory pass) ^2</td>
    </tr>
    <tr>
      <td>Board RAM (<code class="language-plaintext highlighter-rouge">qualia host</code>)</td>
      <td style="text-align: right">3.5</td>
      <td>GB</td>
      <td>T29 comment ^3</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/</code> free on board</td>
      <td style="text-align: right">161</td>
      <td>GiB</td>
      <td>T29 comment ^3</td>
    </tr>
    <tr>
      <td>Native board build of the CLI subset</td>
      <td style="text-align: right">~30</td>
      <td>s</td>
      <td>T29 comment ^3</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">QUALIA_LEASH_BASE_URL</code> code consumers</td>
      <td style="text-align: right">0</td>
      <td>—</td>
      <td>T29 comment ^3</td>
    </tr>
    <tr>
      <td>Default agent URL</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">https://127.0.0.1:8080</code></td>
      <td>—</td>
      <td>T29 comment ^3</td>
    </tr>
  </tbody>
</table>

<p>^1 Captured on the dev host’s WSL2 under <code class="language-plaintext highlighter-rouge">nsys</code> in an earlier session than the board work; the 4090
is shared, so durations are one contended sample and launch count/shape are the stable part.
^2 Pinkie, native aarch64, <code class="language-plaintext highlighter-rouge">ncu</code> — the first board capture in the tree. Manual, because the board has
no <code class="language-plaintext highlighter-rouge">nsys</code> and no mage. Durations are ncu’s isolated replay, not a throughput measurement.
^3 The T29 deploy smoke at <code class="language-plaintext highlighter-rouge">25f2b6f7</code>, taken in a session different from both captures.</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/25f2b6f...f6893d2"><code class="language-plaintext highlighter-rouge">25f2b6f..f6893d2</code></a> — the first board deploy through the merge
of the T50 Pinkie capture. This entry’s epic is
<a href="https://github.com/superposition/qualia/issues/15">EPIC-10 (#15)</a>.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>No mission had run at this entry’s endpoint.</strong> The epic’s actual acceptance — open one exploration
mission, watch <code class="language-plaintext highlighter-rouge">open_missions</code> go 1 then 0, see a sealed MCAP segment, the same mission id in the
session list and the GUI and the same generation in the TUI — had not been attempted in this entry’s
period, which ends at <code class="language-plaintext highlighter-rouge">f6893d2</code> (2026-09-11T17:55:18Z). See the note in “What we tried” for what has
run since.</li>
  <li><strong>The first board run could not even reach a server.</strong> At <code class="language-plaintext highlighter-rouge">25f2b6f7</code>, <code class="language-plaintext highlighter-rouge">runners/agent</code> and
<code class="language-plaintext highlighter-rouge">crates/braid</code> were one-line stubs and <code class="language-plaintext highlighter-rouge">qualia-init</code> had no binary, so <code class="language-plaintext highlighter-rouge">qualia run</code> refused and
<code class="language-plaintext highlighter-rouge">qualia health</code>/<code class="language-plaintext highlighter-rouge">planner</code> hung on <code class="language-plaintext highlighter-rouge">curl</code> with no <code class="language-plaintext highlighter-rouge">-m</code>; <code class="language-plaintext highlighter-rouge">0/10</code> manifest runners were active. The
layers that now exist were in flight then. This is a snapshot of a stack that could not start, not a
measurement of the one that can.</li>
  <li><strong>The 8.19× divides two different profilers.</strong> The board number is an <code class="language-plaintext highlighter-rouge">ncu</code> isolated replay with its
default clock <em>and</em> cache control; the 4090 number is an <code class="language-plaintext highlighter-rouge">nsys</code> wall-clock capture from a different
host and commit. Shapes and launch counts are the comparable part; the ratio is indicative.</li>
  <li><strong>One board capture, and the board was shared.</strong> Other agents were building and running on Pinkie
in the same window; <code class="language-plaintext highlighter-rouge">belief_update</code> was captured five times across the session with a 0.21 % spread,
so contention moved the second decimal, not the number — but the runs are reported as agreeing
rather than undisturbed.</li>
  <li><strong>The memory budget is unproven on the board.</strong> The ≤ 6 GiB plan and the <code class="language-plaintext highlighter-rouge">sm_87</code>/<code class="language-plaintext highlighter-rouge">sm_89</code> fatbin
targets were T18 (<code class="language-plaintext highlighter-rouge">#33</code>, then <code class="language-plaintext highlighter-rouge">status:ready</code>); T18 has since landed (<code class="language-plaintext highlighter-rouge">60beee4</code>, PR #207, merged
2026-09-11T20:16:14Z, capture at <code class="language-plaintext highlighter-rouge">docs/evidence/T18/fatbin-sm-87/</code>). Nothing in this entry shows the
stack fitting in the board’s 8 GB.</li>
  <li><strong>The board clock is about 10 days behind</strong> (<code class="language-plaintext highlighter-rouge">date -u</code> read 2026-09-01 when the host read
2026-09-11), which the deploy comment flags as a hazard for anything depending on TLS to a remote
upstream; nothing in this entry depends on it.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="cuda" /><category term="jetson" /><category term="profiling" /><category term="deployment" /><summary type="html"><![CDATA[The same 13 CUDA launches cost 4.78 ms on the RTX 4090 and 39.18 ms on the Orin NX — 8.19×, with residency ruled out as the cause — and the first deploy of the stack to the board found a hang, not a mission.]]></summary></entry><entry><title type="html">The mark</title><link href="https://superposition.github.io/journal/the-mark/" rel="alternate" type="text/html" title="The mark" /><published>2026-09-11T17:00:00-04:00</published><updated>2026-09-11T17:00:00-04:00</updated><id>https://superposition.github.io/journal/the-mark</id><content type="html" xml:base="https://superposition.github.io/journal/the-mark/"><![CDATA[<p><strong>The claim.</strong> The sites’ wordmark used to be the glyph <code class="language-plaintext highlighter-rouge">∿</code>; it is now a psi monogram that exists
three ways and can only agree. <code class="language-plaintext highlighter-rouge">assets/mark/psi.json</code> is <strong>738 bytes</strong> — four closed polygon point
lists (stem, left arm, right arm, descender) in a 0..1 unit square, each with a <code class="language-plaintext highlighter-rouge">colour</code> key of <code class="language-plaintext highlighter-rouge">ink</code>
or <code class="language-plaintext highlighter-rouge">accent</code>. <code class="language-plaintext highlighter-rouge">assets/mark/psi.svg</code> is <strong>1191 bytes</strong> generated from it by
<code class="language-plaintext highlighter-rouge">assets/mark/render_mark.py</code> (<strong>8665 bytes</strong>), and <code class="language-plaintext highlighter-rouge">render_mark.py --check</code> exits non-zero when the
committed SVG differs. The SVG is viewBox <code class="language-plaintext highlighter-rouge">0 0 100 100</code>, geometry inset <strong>8</strong> units, stroke <strong>0.085</strong>
unit-square units (which renders as <strong>7.14</strong> viewBox units), square caps, mitred joins, <code class="language-plaintext highlighter-rouge">#edf0f5</code>
for stem and arms, <code class="language-plaintext highlighter-rouge">#91dbba</code> for the descender, transparent, <strong>zero</strong> <code class="language-plaintext highlighter-rouge">&lt;text&gt;</code> elements, content
bounding box <code class="language-plaintext highlighter-rouge">18.5,15.5..81,84</code>. The extruded version is a Blender script whose <strong>two runs are
byte-identical for all six outputs</strong>. One source, three renderings, no drift.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-mark/mark-geometry.svg" width="1100" height="481" alt="Two panels computed from psi.json: left, the centre-line length in viewBox units of each monogram part (stem, left arm, right arm, descender); right, each part's x-extent and y-extent in viewBox units." />
  </picture>
  <figcaption>
    <p>Two panels computed from <code>assets/mark/psi.json</code>: left, each part's centre-line length
    in viewBox units; right, each part's x-extent and y-extent. The chart describes the geometry
    source, not the mark as rendered.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>The geometry was moved out of the journal repo.</strong> Step 39 says the mark is authored “in the journal
repo”. The decision that survived (D-007) is the opposite: <code class="language-plaintext highlighter-rouge">superposition/qualia</code> owns
<code class="language-plaintext highlighter-rouge">assets/mark/{psi.json,render_mark.py,psi.svg}</code>, so the flat mark and the 3D mesh cannot drift from
each other or from a second copy, and the sites receive inlined geometry later. T41’s handoff is a
patch to the sites, not a push.</p>

<p><strong>The crash left a file of NUL bytes.</strong> The session that started T40 died mid-write:
<code class="language-plaintext highlighter-rouge">assets/mark/build_mark.py</code> was NUL-filled — the ticket’s two comments report the size as 24,106 and
31,261 NUL bytes, and the discrepancy is left as recorded rather than reconciled — and the six
artifacts beside it were of unknown provenance. Nothing from that session was kept. The script was re-authored in the repository and every
artifact regenerated from it, then proved by running the whole pipeline twice from two fresh copies.</p>

<p><strong>Two sources of nondeterminism had to be closed, and only two were found.</strong> Blender stamps PNG
<code class="language-plaintext highlighter-rouge">Date</code>/<code class="language-plaintext highlighter-rouge">RenderTime</code> metadata, so those are switched off in the script; and the threaded exact boolean
returns element faces in an order that varies, so the combined mesh is rebuilt in a canonical face
order before export. With both closed, the GLB and the five rasters compare byte-identical across
runs. The search for a third is not claimed to be exhaustive — it is claimed that two independent runs
agree on every file.</p>

<p><strong>The SVG importer reads fills and ignores strokes, so the pipeline took a documented detour.</strong> Step
40 says to import <code class="language-plaintext highlighter-rouge">psi.svg</code>, convert curves to mesh and extrude. Blender’s <code class="language-plaintext highlighter-rouge">io_curve_svg</code> imports the
closed polygons’ centre lines and drops the stroke entirely; extruding zero-width lines produces
nothing. The script therefore takes the centre lines from the imported SVG, checks them against
<code class="language-plaintext highlighter-rouge">psi.json</code>, and strokes them under the SVG’s own cap, join and mitre-limit rules before extruding by
<strong>0.12</strong> and bevelling by <strong>0.01</strong> in two segments. The deviation is written in the script, not
smuggled past the ticket.</p>

<h2 id="why-geometry-and-not-a-glyph">Why geometry and not a glyph</h2>

<p>A glyph is a font’s opinion. It renders differently in every browser, cannot be extruded honestly, and
cannot be checked. Geometry can be checked: <code class="language-plaintext highlighter-rouge">render_mark.py --check</code> regenerates the SVG and fails if
the bytes differ, so an edit to <code class="language-plaintext highlighter-rouge">psi.json</code> that is not re-rendered is caught. The renderer is also the
mark’s only rasteriser in this phase — Blender renders the icons at 512, 180 and 32 pixels from the
same camera and the same mesh, rather than shelling out to <code class="language-plaintext highlighter-rouge">inkscape</code>, <code class="language-plaintext highlighter-rouge">rsvg-convert</code> or ImageMagick.</p>

<p>The shape itself is deliberate: a vertical stem with two arms sweeping outward and up from below its
head, tapering to points at roughly <strong>33°</strong> from horizontal, so the monogram cannot be misread as a
plus, plus an accent descender below the baseline. The unit square maps as $v’ = 8 + 84v$ — the
8-unit inset the ticket fixes — so a stroke of <code class="language-plaintext highlighter-rouge">0.085</code> in unit-square coordinates is <code class="language-plaintext highlighter-rouge">7.14</code> viewBox
units wide. Both numbers are stated in the SVG comment and in the script.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-mark/mark-anatomy.svg" width="704" height="704" alt="The four parts of the monogram stroked at psi.json's proportions inside the inset-8, viewBox-100 frame psi.svg draws: stem and arms in ink, the descender in accent, each part in a box naming its centre-line length." />
  </picture>
  <figcaption>
    <p>The four parts stroked at the geometry source's proportions inside the inset-8, viewBox-100
    frame <code>psi.svg</code> draws — stem and arms in ink <code>#edf0f5</code>, the descender in
    accent <code>#91dbba</code>, each part in a box naming its centre-line length.</p>
  </figcaption>
</figure>

<figure class="measurement">
  <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.5.0/model-viewer.min.js"></script>
  <model-viewer src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-mark/turntable.glb" camera-controls="" auto-rotate="" disable-zoom=""></model-viewer>
  <figcaption>
    <p>The extruded mark plus one pillar per part of <code>psi.json</code>, each pillar's height the
    part's centre-line length — the chart's number — with a 60-frame rotation baked as an animation.
    If the viewer script does not load, the same
    <a href="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-mark/turntable.glb">GLB
    downloads from the same figure</a>.</p>
  </figcaption>
</figure>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">psi.json</code></td>
      <td style="text-align: right">738</td>
      <td>bytes</td>
      <td>T39 comment ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">render_mark.py</code></td>
      <td style="text-align: right">8665</td>
      <td>bytes</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">psi.svg</code></td>
      <td style="text-align: right">1191</td>
      <td>bytes</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">psi.svg</code> SHA-256 (prefix)</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">42be74cb…272436</code></td>
      <td>—</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td>Polygon lists in the source</td>
      <td style="text-align: right">4</td>
      <td>polygons</td>
      <td><code class="language-plaintext highlighter-rouge">psi.json</code></td>
    </tr>
    <tr>
      <td>Stroke width</td>
      <td style="text-align: right">0.085 → 7.14</td>
      <td>unit-square → viewBox</td>
      <td><code class="language-plaintext highlighter-rouge">psi.svg</code> comment</td>
    </tr>
    <tr>
      <td>Extrusion / bevel</td>
      <td style="text-align: right">0.12 / 0.01, 2 segments</td>
      <td>unit-square</td>
      <td><code class="language-plaintext highlighter-rouge">build_mark.py</code></td>
    </tr>
    <tr>
      <td>Raster sizes</td>
      <td style="text-align: right">512, 180, 32</td>
      <td>pixels</td>
      <td>epic Step 40, <code class="language-plaintext highlighter-rouge">build_mark.py</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">--check</code> on a clean tree</td>
      <td style="text-align: right">exit 0 (exit 1 after mutating <code class="language-plaintext highlighter-rouge">psi.json</code>)</td>
      <td>exit code</td>
      <td>T39 comment ^1</td>
    </tr>
    <tr>
      <td>Blender runs byte-identical</td>
      <td style="text-align: right">6 of 6</td>
      <td>files</td>
      <td>T40 comment ^2</td>
    </tr>
    <tr>
      <td>NUL bytes recovered from the crash</td>
      <td style="text-align: right">31,261</td>
      <td>bytes</td>
      <td>T40 comment ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">&lt;text&gt;</code> elements in the SVG</td>
      <td style="text-align: right">0</td>
      <td>elements</td>
      <td>T39 comment ^1</td>
    </tr>
  </tbody>
</table>

<p>^1 Measured when the mark landed, in a session different from the Blender work.
^2 Measured in the T40 session, which re-authored the script after the crash; the byte-identity
comparison is between two runs from two fresh copies on the same host and Blender version
(4.3.2).</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/a2c1440...ce04eaf"><code class="language-plaintext highlighter-rouge">a2c1440..ce04eaf</code></a> — the geometry source through the merge
of the Blender pipeline. Its epic is <a href="https://github.com/superposition/qualia/issues/13">EPIC-11 (#13)</a>;
tickets <a href="https://github.com/superposition/qualia/issues/56">T39 #56</a> and
<a href="https://github.com/superposition/qualia/issues/57">T40 #57</a> are the tickets described here;
<a href="https://github.com/superposition/qualia/issues/58">T41 #58</a> landed just after this entry’s period.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>The sites were wired after this entry’s period.</strong> T41 (<code class="language-plaintext highlighter-rouge">#58</code>) landed in <code class="language-plaintext highlighter-rouge">6894d7f</code> (PR #203,
merged 2026-09-11T19:31:10Z); its two site legs merged a few minutes earlier —
<code class="language-plaintext highlighter-rouge">superposition/superposition.github.io#16</code> (merge <code class="language-plaintext highlighter-rouge">ccd441b</code>, 2026-09-11T19:24:49Z) and
<code class="language-plaintext highlighter-rouge">superposition/mage#82</code> (merge <code class="language-plaintext highlighter-rouge">7a798f6</code>, 2026-09-11T19:24:53Z) — so both sites now carry the inlined
four-path wordmark and the 180×180 touch icon, and <code class="language-plaintext highlighter-rouge">assets/mark/install_mark.py --check</code> proves the
installed copies have not drifted.</li>
  <li><strong>The hero and turntable landed after this entry’s period.</strong> T42 (<code class="language-plaintext highlighter-rouge">#59</code>, one hero render per
milestone entry) and T43 (<code class="language-plaintext highlighter-rouge">#60</code>, one turntable GLB per entry with a download fallback) landed in
PR #206 (<code class="language-plaintext highlighter-rouge">b6dfda6</code>, merged 2026-09-11T19:59:10Z) and PR #205 (<code class="language-plaintext highlighter-rouge">3cf3706</code>, merged
2026-09-11T20:02:41Z); T43’s <code class="language-plaintext highlighter-rouge">02909f4</code> committed the three figures this entry now carries under
<code class="language-plaintext highlighter-rouge">docs/figures/the-mark/</code> — <code class="language-plaintext highlighter-rouge">mark-geometry.svg</code>, <code class="language-plaintext highlighter-rouge">mark-anatomy.svg</code> and <code class="language-plaintext highlighter-rouge">turntable.glb</code>. The mark
itself is not among the entries T42 gave a hero: <code class="language-plaintext highlighter-rouge">c9f77f0</code> added <code class="language-plaintext highlighter-rouge">hero.webp</code> to the three milestone
entries <a href="https://superposition.github.io/journal/the-connectome-as-a-prior/"><code class="language-plaintext highlighter-rouge">the-connectome-as-a-prior</code></a>,
<a href="https://superposition.github.io/journal/the-ladder/"><code class="language-plaintext highlighter-rouge">the-ladder</code></a> and
<a href="https://superposition.github.io/journal/the-front-end-rebuilt-from-lessons/"><code class="language-plaintext highlighter-rouge">the-front-end-rebuilt-from-lessons</code></a>, and not
to this one.</li>
  <li><strong>Byte-identity is per host and per Blender version.</strong> Two runs agree on this workstation with
Blender 4.3.2. A different Blender release is a different rasteriser and may not reproduce the same
bytes; no cross-version or cross-machine comparison was made.</li>
  <li><strong>The 33° reading is a design description, not a measurement.</strong> The arm angle comes from how the
polygon points were authored; no instrument measured it.</li>
  <li><strong>The mark has never been seen at 32 pixels by a human in this record.</strong> The icon rasters are
produced deterministically; whether the 32-pixel icon is legible is a judgement the ticket asserts
by construction (“the flat camera is what makes the 32-pixel icon legible”) and no reader test is
recorded.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="mark" /><category term="blender" /><category term="determinism" /><category term="assets" /><summary type="html"><![CDATA[The psi monogram as geometry — a 738-byte JSON file, an SVG generated from it, and a Blender pipeline whose two runs are byte-identical — with the flat mark and the 3D mesh unable to drift apart.]]></summary></entry><entry><title type="html">The ladder</title><link href="https://superposition.github.io/journal/the-ladder/" rel="alternate" type="text/html" title="The ladder" /><published>2026-09-11T16:55:00-04:00</published><updated>2026-09-11T16:55:00-04:00</updated><id>https://superposition.github.io/journal/the-ladder</id><content type="html" xml:base="https://superposition.github.io/journal/the-ladder/"><![CDATA[<p><strong>The claim.</strong> The seam between the neural and symbolic halves is a single measured number: how far
the observed latent sits from what the predictor expected. <code class="language-plaintext highlighter-rouge">crates/braid/src/drift.rs</code> computes
<code class="language-plaintext highlighter-rouge">qualia_jepa::diagonal_mahalanobis_squared(latent, predicted_mean, precision)</code> with
<code class="language-plaintext highlighter-rouge">precision = exp(-log_variance)</code> — the crate’s <strong>squared</strong> distance, the number a threshold compares —
and returns <code class="language-plaintext highlighter-rouge">DriftReport { mahalanobis, sample_count }</code>. Identity prediction is exactly <strong>0.0</strong>; ragged,
empty or non-finite inputs return <strong>0.0 with <code class="language-plaintext highlighter-rouge">sample_count</code> 0</strong>, the mute pair, so a malformed sample
fires no rule. Around it, the rule table exists as data: four <code class="language-plaintext highlighter-rouge">default_rules()</code> in a fixed order, the
first of which lowers coupling by a factor of <strong>0.90</strong> on a failed mission. <code class="language-plaintext highlighter-rouge">qualia-braid</code> finished at
<strong>17 tests</strong> on the board for the drift half and <strong>24 tests</strong> with the rules. The ladder those
thresholds describe — recalibrate, roll back, observe-only, safe stop — is <strong>not in the tree yet</strong>;
what has landed is the measurement and the rules, and that distinction is the point of this entry.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-ladder/hero.webp" width="1100" height="619" alt="The extruded psi monogram beside four concentric extruded rings, the widening gaps between them at squared Mahalanobis 3, 5 and 8." />
  </picture>
  <figcaption>
    <p>The extruded mark beside the healing ladder's four bands as four concentric rings, the gaps
    between them at squared Mahalanobis 3, 5 and 8. The outermost band is open-ended: the ladder's
    thresholds are the plan's specification, not a measurement.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>The measurement was not re-derived.</strong> <code class="language-plaintext highlighter-rouge">crates/jepa</code> already exports the Mahalanobis routine the
model’s own NLL uses, so the braid calls it instead of writing a second one. The reference tree has no
<code class="language-plaintext highlighter-rouge">braid</code> crate at all, so <code class="language-plaintext highlighter-rouge">drift.rs</code> has no counterpart to match and the ticket text is the whole
interface; reusing the only existing math for the same quantity was the one decision available.</p>

<p><strong>Three inputs had to be made mute, not loud.</strong> The ticket says a length mismatch returns
<code class="language-plaintext highlighter-rouge">sample_count == 0</code> and that <code class="language-plaintext highlighter-rouge">observe</code> treats it as “no opinion”. Review found the rest of the family:
non-finite latents or means, a non-finite log-variance — which would otherwise reach <code class="language-plaintext highlighter-rouge">exp</code> — and a
precision that is not real. All of them return the mute pair. The point is that the drift path cannot
panic a running stack on a bad sample; a rule layer that fires on garbage is worse than one that
abstains.</p>

<p><strong>The first rule table had a rule that cannot fire, and that is recorded, not hidden.</strong> The plan’s
<code class="language-plaintext highlighter-rouge">default_rules()</code> includes <code class="language-plaintext highlighter-rouge">DriftAbove { threshold: 3.0 } → EnterObserveOnly</code>. The braid’s frozen
<code class="language-plaintext highlighter-rouge">BraidEvent</code> vocabulary is a closed set of six variants plus <code class="language-plaintext highlighter-rouge">Unknown</code>, and no variant carries a drift
measurement; T34 shipped <code class="language-plaintext highlighter-rouge">DriftReport</code> without adding a drift event. So <code class="language-plaintext highlighter-rouge">DriftAbove</code> is contract data
that fires against no event <code class="language-plaintext highlighter-rouge">evaluate</code> can be handed today. The ticket’s text was left as written and
the gap was pinned by a test — <code class="language-plaintext highlighter-rouge">the_drift_rule_fires_on_no_event_the_braid_carries_yet</code> — rather than
inventing a variant the ticket does not name. The drift reaches the healing ladder directly, when the
ladder exists.</p>

<p><strong>Falsification, not just green.</strong> For the rules, two deliberate mutations (swap the first two default
rules; ignore the matched outcome) were built and both were caught, <code class="language-plaintext highlighter-rouge">EXIT=101</code>; reverted, the suite
went green again. For the drift tests, they were written before <code class="language-plaintext highlighter-rouge">drift.rs</code> existed and failed with
<code class="language-plaintext highlighter-rouge">E0432: unresolved import qualia_braid::drift</code>.</p>

<h2 id="the-ladder-is-the-tickets-contract-not-a-measurement">The ladder is the ticket’s contract, not a measurement</h2>

<p>The epic’s Step 35 fixes the escalation, and it is worth writing down exactly because none of it runs
yet — these are thresholds from the plan, and no code in the tree compares a drift to them:</p>

<table>
  <thead>
    <tr>
      <th>Condition</th>
      <th>Step</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">mahalanobis &lt;= 3.0</code></td>
      <td>none</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">mahalanobis &lt;= 5.0</code></td>
      <td>recalibrate (through the registry’s calibration gate)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">mahalanobis &lt;= 8.0</code></td>
      <td>roll back to the previous generation</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">mahalanobis &gt; 8.0</code>, or <code class="language-plaintext highlighter-rouge">attempts &gt;= 3</code></td>
      <td>observe-only</td>
    </tr>
    <tr>
      <td>observe-only held <strong>10 s</strong> with drift still above 8.0</td>
      <td>request a safe stop</td>
    </tr>
  </tbody>
</table>

<p><code class="language-plaintext highlighter-rouge">SafeStop</code> produces a <strong>request</strong>: the agent forwards it to leash and leash decides, exactly as the
compute API’s authority statement requires. No function in the crate may call a motor, and no test may
assert that it does. The numbers above are the plan’s; the only measured quantities in this entry are
the drift values and the test counts.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-ladder/ladder-bands.svg" width="1100" height="516" alt="The healing ladder's escalation over squared Mahalanobis distance: four bands separated at 3, 5 and 8, each labelled with the step it selects, and the measured identity-prediction drift of 0.0 marked on the axis." />
  </picture>
  <figcaption>
    <p>The ladder's escalation as four bands, separated at the plan's 3, 5 and 8 and labelled with the
    step each selects; the measured identity-prediction drift (<code>0.0</code>) is marked on the axis.
    The chart says on its face that the thresholds are a specification, not a measurement.</p>
  </figcaption>
</figure>

<h2 id="what-the-rules-say-in-order">What the rules say, in order</h2>

<p><code class="language-plaintext highlighter-rouge">default_rules()</code> returns, in this order:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">MissionClosed { outcome: "failed" } → LowerCoupling { factor: 0.90 }</code></li>
  <li><code class="language-plaintext highlighter-rouge">PromotionRolledBack → EnterObserveOnly</code></li>
  <li><code class="language-plaintext highlighter-rouge">Quarantined → RequestTraining</code> — a quarantine is a reason to learn from what survived</li>
  <li><code class="language-plaintext highlighter-rouge">DriftAbove { threshold: 3.0 } → EnterObserveOnly</code></li>
</ol>

<p>Rules are data, so a later rule set is a new vector and not a code change. What is <em>measured</em> about
them is their order and their effect on the events the braid can receive: the seven tests cover the
table, and the board re-ran the whole crate at 24 passed.</p>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Identity-prediction drift</td>
      <td style="text-align: right">0.0</td>
      <td>squared Mahalanobis</td>
      <td><code class="language-plaintext highlighter-rouge">drift_is_zero_for_identity_prediction</code></td>
    </tr>
    <tr>
      <td>Mute pair for a bad sample</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0.0</code> / <code class="language-plaintext highlighter-rouge">0</code></td>
      <td>distance / samples</td>
      <td><code class="language-plaintext highlighter-rouge">mismatched_sample_is_no_opinion</code></td>
    </tr>
    <tr>
      <td>Drift tests, host</td>
      <td style="text-align: right">3 passed / 0 failed</td>
      <td>tests</td>
      <td>T34 comment ^1</td>
    </tr>
    <tr>
      <td>Drift tests, Pinkie aarch64</td>
      <td style="text-align: right">6 passed / 0 failed</td>
      <td>tests</td>
      <td>Board3 comment, PR #195 ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-braid</code> on Pinkie (T34)</td>
      <td style="text-align: right">17 passed / 0 failed</td>
      <td>tests</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-braid</code> on Pinkie (T33)</td>
      <td style="text-align: right">24 passed / 0 failed</td>
      <td>tests</td>
      <td>Board3 comment, PR #200 ^2</td>
    </tr>
    <tr>
      <td>Coupling factor on failure</td>
      <td style="text-align: right">0.90</td>
      <td>factor</td>
      <td><code class="language-plaintext highlighter-rouge">crates/braid/src/rules.rs</code></td>
    </tr>
    <tr>
      <td>Drift rule threshold</td>
      <td style="text-align: right">3.0</td>
      <td>squared Mahalanobis</td>
      <td><code class="language-plaintext highlighter-rouge">crates/braid/src/rules.rs</code></td>
    </tr>
    <tr>
      <td>Files compared by the provenance gate</td>
      <td style="text-align: right">152 authored, 0 identical</td>
      <td>files</td>
      <td>T34 comment ^1</td>
    </tr>
    <tr>
      <td>Ladder thresholds 3 / 5 / 8, hold 10</td>
      <td style="text-align: right">—</td>
      <td>squared Mahalanobis, s</td>
      <td>epic Step 35 text ^3</td>
    </tr>
  </tbody>
</table>

<p>^1 Host tests on the dev workstation in a different session from the board runs.
^2 Pinkie, native aarch64, from a <code class="language-plaintext highlighter-rouge">git archive</code> of the head; <code class="language-plaintext highlighter-rouge">qualia-braid</code> has no binary, so
<code class="language-plaintext highlighter-rouge">cargo test -p qualia-braid</code> is its own smoke path.
^3 The 3, 5, 8 and 10 s values are the plan’s specification, not measured behaviour. No code in the
tree compares a drift to them.</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/7cac730...7b3bd15"><code class="language-plaintext highlighter-rouge">7cac730..7b3bd15</code></a> — the drift commit through the merge of
T34. The rule layer landed in <code class="language-plaintext highlighter-rouge">2891580</code> (PR #200, <code class="language-plaintext highlighter-rouge">2602c4d</code>, merged 2026-09-11T19:25:47Z). This
entry’s epic is
<a href="https://github.com/superposition/qualia/issues/11">EPIC-08C (#11)</a>; tickets
<a href="https://github.com/superposition/qualia/issues/49">T33 #49</a> and
<a href="https://github.com/superposition/qualia/issues/50">T34 #50</a>.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>The ladder has not landed.</strong> As of 2026-09-11T20:45Z, <code class="language-plaintext highlighter-rouge">crates/braid/src/heal.rs</code> was not in
<code class="language-plaintext highlighter-rouge">main</code>; T35 (<code class="language-plaintext highlighter-rouge">#51</code>) was <code class="language-plaintext highlighter-rouge">status:claimed</code>, with the ladder on PR #209 (<code class="language-plaintext highlighter-rouge">ticket/T35</code>, head <code class="language-plaintext highlighter-rouge">d8b05af</code>,
open), and T36 (<code class="language-plaintext highlighter-rouge">#52</code>, the authority bound on safe stop) was still <code class="language-plaintext highlighter-rouge">status:ready</code>. So no step has
been selected from a real drift, no rollback has been requested, and no safe stop has been
requested.</li>
  <li><strong>The drift thresholds are uncalibrated.</strong> 3, 5 and 8 are the plan’s numbers. No run has measured
what a <em>normal</em> drift looks like on this stack, so there is no evidence that these values separate
“fine” from “recalibrate”.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">DriftAbove</code> fires on nothing.</strong> As above: the braid carries no drift event, so the fourth default
rule is inert until the wire does.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">measure</code> has no board capture.</strong> Step 47 lists T35 as one of three mandatory <code class="language-plaintext highlighter-rouge">needs:profile</code>
captures — the ladder’s decision path as a CPU timeline, with no kernel in it — and that capture
cannot exist until the decision path does.</li>
  <li><strong>Drift is a number, not a diagnosis.</strong> A large squared Mahalanobis says the latent is far from the
predicted mean under the predicted precision; it does not say whether the model is wrong, the world
changed, or the precision estimate is bad. The ladder is a policy over that number, and the policy
is untested.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="braid" /><category term="drift" /><category term="neuro-symbolic" /><category term="healing" /><summary type="html"><![CDATA[The neuro-symbolic seam as one number — squared Mahalanobis distance from the predictor's mean, computed with the JEPA crate's own routine — plus a rule table, and a healing ladder that is still only a specification.]]></summary></entry><entry><title type="html">The agent in the loop</title><link href="https://superposition.github.io/journal/the-agent-in-the-loop/" rel="alternate" type="text/html" title="The agent in the loop" /><published>2026-09-11T16:50:00-04:00</published><updated>2026-09-11T16:50:00-04:00</updated><id>https://superposition.github.io/journal/the-agent-in-the-loop</id><content type="html" xml:base="https://superposition.github.io/journal/the-agent-in-the-loop/"><![CDATA[<p><strong>The claim.</strong> The agent now has one place where strands report and one view they report into. A
<em>strand</em> is one part of the stack that reports events into that state — at this edge, three owners: the
mission broker, the evidence recorder and the JEPA runtime; the crate’s vocabulary is one variant
wider, recovery’s <code class="language-plaintext highlighter-rouge">Quarantined</code> being a dispatch rather than a strand report — and the <em>braid</em> is the
state itself: a state machine plus a dispatch that <strong>stores nothing</strong>, since the durable copies stay
in MCAP, SQLite and the registry and <code class="language-plaintext highlighter-rouge">observe</code> is the only mutator. Two of the three strands are
separate processes and cannot call it in the agent’s address space, so the ticket grew a write edge:
<code class="language-plaintext highlighter-rouge">POST /braid</code> carrying the frozen <code class="language-plaintext highlighter-rouge">BraidEvent</code> envelope, beside the read <code class="language-plaintext highlighter-rouge">GET /braid</code>. The board
accepted it: with the TLS surface up, <code class="language-plaintext highlighter-rouge">POST /braid mission_opened</code> returned <strong>HTTP 200</strong> and the
follow-up read showed <code class="language-plaintext highlighter-rouge">open_missions</code> <strong>0 → 1</strong>; <code class="language-plaintext highlighter-rouge">GET /braid</code> answers
<code class="language-plaintext highlighter-rouge">{"schema_version":"qualia.braid-state.v1", …}</code>. On the same board, <code class="language-plaintext highlighter-rouge">qualia-agent</code> finished at
<strong>41 passed / 0 failed</strong>. And the fly is in the loop quantitatively: at stack start the runner opens
<code class="language-plaintext highlighter-rouge">explore-frontier</code> and sends <code class="language-plaintext highlighter-rouge">fly prior: risk uncertainty_weight=0.625 semantic_novelty=0</code>.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-agent-in-the-loop/strand-flow.svg" width="1100" height="784" alt="The strands fanning into the one write edge, POST /braid carrying the frozen BraidEvent (503 on a failed dispatch, a quarantined report refused with 400), then observe as the sole mutator, the folded BraidState and its six fields, the durable copies the braid does not keep (MCAP quarantine, the registry's rollback record), and the GET /braid read the console, TUI and operator page poll." />
  </picture>
  <figcaption>
    <p>The strands reporting into <code>observe</code> through the one write edge —
    <code>POST /braid</code> carrying the frozen <code>BraidEvent</code> (503 on a failed dispatch, a
    <code>quarantined</code> report refused with 400) — then <code>observe</code> as the sole
    mutator, the folded <code>BraidState</code> and its six fields, the durable copies the braid
    keeps none of, and the <code>GET /braid</code> read the console, TUI and operator page poll.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>The rollback dispatch was deferred, with a failing test to prove it.</strong> Step 19 says <code class="language-plaintext highlighter-rouge">observe</code> calls
the registry’s existing rollback. The fixed interface,
<code class="language-plaintext highlighter-rouge">observe(state: &amp;mut BraidState, event: &amp;BraidEvent)</code>, is synchronous and carries a
<code class="language-plaintext highlighter-rouge">PromotionRolledBack { generation, reason }</code> with no registry handle and no generation-pointer path;
the registry itself had only a <code class="language-plaintext highlighter-rouge">[[bin]]</code> target and a <code class="language-plaintext highlighter-rouge">fn main() {}</code> at the time, so
<code class="language-plaintext highlighter-rouge">cargo tree -p qualia-braid</code> warned about a dependency with no lib target. Rather than change the
interface the ticket fixes, T19 keeps the state transition (the generation moves, <code class="language-plaintext highlighter-rouge">last_promotion_ns</code>
does not) and the <strong>reason stays on the wire</strong>, asserted by a test that decodes the envelope. The call
moves to C10 (<code class="language-plaintext highlighter-rouge">#76</code>) and the routing to T22 (<code class="language-plaintext highlighter-rouge">#37</code>). A temporary test asserting the braid records the
reason was written first, failed as expected, and was removed; the committed assertion is the one that
stays true.</p>

<p><strong>The braid’s event vocabulary resisted invention.</strong> T19 added one variant, <code class="language-plaintext highlighter-rouge">Unknown</code>, marked
<code class="language-plaintext highlighter-rouge">#[serde(other)]</code>, so a future event decodes and leaves the state untouched — the forward-compatibility
arm the epic’s own test asks for.</p>

<p><strong>The read-only write edge.</strong> The literal step — every strand calls <code class="language-plaintext highlighter-rouge">observe</code> itself — is impossible
for <code class="language-plaintext highlighter-rouge">arena-recorder</code> and <code class="language-plaintext highlighter-rouge">jepa-runtime</code>, which are processes. Main ruled the write edge into the
ticket: body is <code class="language-plaintext highlighter-rouge">crates/braid</code>’s frozen envelope, reply is the view <code class="language-plaintext highlighter-rouge">GET /braid</code> returns, a failed
dispatch is <code class="language-plaintext highlighter-rouge">503</code>, and <code class="language-plaintext highlighter-rouge">AuthScope::Peer</code> (already loopback-bypassed) means co-located runners need no
new secret. The agent’s <code class="language-plaintext highlighter-rouge">src/braid.rs</code> dropped its local mirror of the braid types and now holds the
one <code class="language-plaintext highlighter-rouge">BraidState</code> the process owns.</p>

<p><strong>Board hygiene was found the hard way.</strong> Two later suites died with <code class="language-plaintext highlighter-rouge">SIGBUS</code> because the board’s
<code class="language-plaintext highlighter-rouge">/dev/shm</code> was <strong>100 % full</strong> — 33 stale 64 MiB <code class="language-plaintext highlighter-rouge">qualia*</code> test regions, about 1.8 GB, owned by no live
process. After <code class="language-plaintext highlighter-rouge">rm -f /dev/shm/qualia*</code> (100 % → 1 %) the same commands were green. It is reported in
the board comment and every later board leg checks <code class="language-plaintext highlighter-rouge">df -h /dev/shm</code> first. A parallel test-isolation
defect (<code class="language-plaintext highlighter-rouge">ShmError::OsError(17)</code> from two smoke tests naming one region) was fixed with a per-test
region name and re-run green.</p>

<h2 id="pacing-the-map-degrades-it-does-not-stop">Pacing: the map degrades, it does not stop</h2>

<p><code class="language-plaintext highlighter-rouge">QUALIA_BELIEF_PACE_MS</code> (default <strong>250</strong>) gates <code class="language-plaintext highlighter-rouge">runners/map</code> and <code class="language-plaintext highlighter-rouge">runners/pose</code>: before publishing,
wait until the newest accepted belief commit is younger than the window; if none has been committed
for <strong>8×</strong> the window, publish anyway and log
<code class="language-plaintext highlighter-rouge">belief pace: stale, publishing map/pose at {lag} ms</code>. A live probe of the real <code class="language-plaintext highlighter-rouge">qualia-pose</code> binary
with a belief tick 300 ms old and <code class="language-plaintext highlighter-rouge">QUALIA_BELIEF_PACE_MS=200</code> held the first pose for <strong>1.3 s</strong>, then
logged <code class="language-plaintext highlighter-rouge">qualia-pose: belief pace: stale, publishing pose at 1604 ms</code> (a second run read 1605 ms). That
is the design in one line: navigation slows, it does not deadlock. Nothing in the step writes to the
ROS graph; leash remains the mapping/localization provider boundary.</p>

<p>The other half of Step 24b is the clock. <code class="language-plaintext highlighter-rouge">BeliefClock::decision_latency_ns()</code> reads the newest
<code class="language-plaintext highlighter-rouge">BeliefSlot</code> timestamp across the eight layers, subtracts the newest finished ledger row, and returns
zero when either side is absent or when a ledger row reads newer than the belief — zero rather than a
wrapped subtraction. It sits on an arena view, not on <code class="language-plaintext highlighter-rouge">BraidState</code>, because the braid’s state is
serialised to JSON at <code class="language-plaintext highlighter-rouge">GET /braid</code> and holds no mapping. T27’s TUI renders it as
<code class="language-plaintext highlighter-rouge">belief lag: {ms} ms</code>.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-agent-in-the-loop/mission-lifecycle.svg" width="1100" height="490" alt="Two panels. Left: open_missions through the fold — the crate's test folding open m1, open m2, close m1, close m2 and a close for a mission it never saw (1, 2, 1, 0, 0), and the agent's write edge folding one open and one close (1, 0). Right: the belief pace gate — the window (1x), the stale window (8x), the hold region, and the two stale publications runners/map's tests assert." />
  </picture>
  <figcaption>
    <p>The lifecycle and the gate: left, <code>open_missions</code> through the fold (1, 2, 1, 0, 0 —
    including a close for a mission it never saw) and the write edge's (1, 0); right, the belief pace
    gate — the window (1×), the stale window (8×), the hold region, and the two stale publications
    <code>runners/map</code>'s tests assert (a 10 s-old tick under the 250 ms default; a 300 ms-old
    tick released at 200 × 8 = 1,600 ms).</p>
  </figcaption>
</figure>

<h2 id="the-exploration-mission-and-one-field-that-could-not-be-computed">The exploration mission, and one field that could not be computed</h2>

<p><code class="language-plaintext highlighter-rouge">runners/explore</code> now opens <code class="language-plaintext highlighter-rouge">MissionOpened { mission_id: "explore-frontier" }</code> at stack start and puts
the fly prior into the planner request’s existing <code class="language-plaintext highlighter-rouge">belief_risk</code> block. <code class="language-plaintext highlighter-rouge">uncertainty_weight</code> is the
prior’s total applied weight <strong>divided by the number of coupled types</strong> — the mean applied weight per
type. The raw total was tried first and rejected by review: <code class="language-plaintext highlighter-rouge">couple</code> sums peak-normalised strengths,
the peak type is always among them, so the sum is always ≥ 1 and the clamp to <code class="language-plaintext highlighter-rouge">0.0..=1.0</code> made the
field a de-facto boolean. The mean is inside the range by construction and reads <code class="language-plaintext highlighter-rouge">0.625</code> on the board.
<code class="language-plaintext highlighter-rouge">semantic_novelty</code> could not be computed at all: the artifact aggregates <code class="language-plaintext highlighter-rouge">dimorphism</code> away and the
tree has no cell-to-type map, so it is a documented <code class="language-plaintext highlighter-rouge">0.0</code>, and the ticket records the two shapes (a
<code class="language-plaintext highlighter-rouge">male_specific</code> mask section in the artifact, or a typed sidecar) that would make it real.</p>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">POST /braid</code> reply</td>
      <td style="text-align: right">200, <code class="language-plaintext highlighter-rouge">open_missions</code> 0 → 1</td>
      <td>—</td>
      <td>Board3 comment, PR #196 ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-agent</code> on Pinkie</td>
      <td style="text-align: right">41 passed / 0 failed</td>
      <td>tests</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-arena-recorder</code> on Pinkie</td>
      <td style="text-align: right">14 passed / 0 failed</td>
      <td>tests</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-jepa-runtime</code> on Pinkie</td>
      <td style="text-align: right">9 passed / 0 failed</td>
      <td>tests</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td>Stale belief regions before clearing</td>
      <td style="text-align: right">33 × 64 MiB (~1.8 GB)</td>
      <td>regions</td>
      <td>same ^1</td>
    </tr>
    <tr>
      <td>Belief pace default</td>
      <td style="text-align: right">250</td>
      <td>ms</td>
      <td><code class="language-plaintext highlighter-rouge">QUALIA_BELIEF_PACE_MS</code>, T21</td>
    </tr>
    <tr>
      <td>Stale window</td>
      <td style="text-align: right">8 × the pace</td>
      <td>—</td>
      <td>T21 comment</td>
    </tr>
    <tr>
      <td>Held first pose in the probe</td>
      <td style="text-align: right">1.3</td>
      <td>s</td>
      <td>T21/T24b comments ^2</td>
    </tr>
    <tr>
      <td>Stale log lag</td>
      <td style="text-align: right">1604 (and 1605)</td>
      <td>ms</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Map tests</td>
      <td style="text-align: right">14 unit + 4 e2e</td>
      <td>tests</td>
      <td>T21 comment</td>
    </tr>
    <tr>
      <td>Pose tests</td>
      <td style="text-align: right">25 unit + 3 e2e</td>
      <td>tests</td>
      <td>ResumeT21 comment</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">uncertainty_weight</code> on Pinkie</td>
      <td style="text-align: right">0.625</td>
      <td>—</td>
      <td>Board1 comment, PR #184 ^1</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">explore</code> tests on Pinkie (after fix)</td>
      <td style="text-align: right">18 passed / 0 failed</td>
      <td>tests</td>
      <td>Board2 comment, PR #184 ^1</td>
    </tr>
    <tr>
      <td>Braid tests on Pinkie (T24b)</td>
      <td style="text-align: right">6 + 4 + 1 passed</td>
      <td>tests</td>
      <td>T24b comment ^1</td>
    </tr>
  </tbody>
</table>

<p>^1 Board runs on Pinkie, native aarch64, from a <code class="language-plaintext highlighter-rouge">git archive</code> of the head; taken in a different
session from the host work in the same ticket.
^2 The 1.3 s hold and the 1604/1605 ms stale line are from two bounded live probes of the real
<code class="language-plaintext highlighter-rouge">qualia-pose</code> binary, in sessions different from the board runs; the pose runner’s own timing, not a
board measurement.</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/bf4c506...f39c114"><code class="language-plaintext highlighter-rouge">bf4c506..f39c114</code></a> — the braid state machine through the
merge that landed the exploration mission. Epics:
<a href="https://github.com/superposition/qualia/issues/7">EPIC-07 (#7)</a>,
<a href="https://github.com/superposition/qualia/issues/8">EPIC-08 (#8)</a>,
<a href="https://github.com/superposition/qualia/issues/9">EPIC-08B (#9)</a>.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>The self-improvement loop has not landed.</strong> As of 2026-09-11T20:45Z, EPIC-08B owed all three
parts: the bounded <code class="language-plaintext highlighter-rouge">QUALIA_FLY_COUPLING_SCALE</code> dial (<code class="language-plaintext highlighter-rouge">#46</code>, <code class="language-plaintext highlighter-rouge">status:claimed</code>), closing the
training/promotion loop through the braid (<code class="language-plaintext highlighter-rouge">#47</code>, <code class="language-plaintext highlighter-rouge">status:claimed</code>) and its failure paths (<code class="language-plaintext highlighter-rouge">#48</code>,
<code class="language-plaintext highlighter-rouge">status:ready</code>). No coupling scale has been clamps-tested, no training job has been submitted by an
agent, and nothing has been promoted.</li>
  <li><strong>T20’s PR merged after this entry’s board leg.</strong> The <code class="language-plaintext highlighter-rouge">POST /braid</code> write edge and the strand
reports are on PR #196, merged 2026-09-11T19:25:44Z in <code class="language-plaintext highlighter-rouge">9fd1e69</code>; the board exercised the head.
T22 (<code class="language-plaintext highlighter-rouge">#37</code>, rollback and quarantine routing) was <code class="language-plaintext highlighter-rouge">status:ready</code> when this entry was written and has
since landed too (<code class="language-plaintext highlighter-rouge">5c304dc</code>, PR #204, merged 2026-09-11T20:06:32Z; <code class="language-plaintext highlighter-rouge">#37</code> closed, <code class="language-plaintext highlighter-rouge">status:review</code>).</li>
  <li><strong>The sync-types <code class="language-plaintext highlighter-rouge">fly_governed</code> field defaults false and has never been true at runtime.</strong> It landed
with the C04 rewrite (<code class="language-plaintext highlighter-rouge">3b4fa66</code>), and the test asserts the default and a round trip, not a mission
that set it.</li>
  <li><strong>The pace probe was one binary in one window.</strong> <code class="language-plaintext highlighter-rouge">map</code> and <code class="language-plaintext highlighter-rouge">pose</code> have unit and end-to-end tests, and
the launch-time stale behaviour was observed once at 1.3 s; no multi-minute soak was run.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">open_missions</code> is a counter, not a mission.</strong> Nothing on the board drove an actual exploration to
completion; the round trip proves the edge, not the behaviour.</li>
  <li><strong>The board was shared.</strong> Other agents were building and running on Pinkie during these legs; the
reported results are agreements across runs, not undisturbed measurements.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="braid" /><category term="agent" /><category term="missions" /><category term="pacing" /><summary type="html"><![CDATA[A braid that stores nothing, a write edge invented because two strands are separate processes, a belief clock that lets the map degrade instead of stopping, and an exploration mission that opens itself — with an uncertainty weight of 0.625 measured on the robot.]]></summary></entry><entry><title type="html">The front end, rebuilt from lessons</title><link href="https://superposition.github.io/journal/the-front-end-rebuilt-from-lessons/" rel="alternate" type="text/html" title="The front end, rebuilt from lessons" /><published>2026-09-11T16:45:00-04:00</published><updated>2026-09-11T16:45:00-04:00</updated><id>https://superposition.github.io/journal/the-front-end-rebuilt-from-lessons</id><content type="html" xml:base="https://superposition.github.io/journal/the-front-end-rebuilt-from-lessons/"><![CDATA[<p><strong>The claim.</strong> The console was built against a document, not against taste. <code class="language-plaintext highlighter-rouge">docs/frontend-lessons.md</code>
reads <strong>five</strong> front ends — the ratatui engine TUI, an egui ops dashboard, a native understanding
viewer, an Ink terminal app and a Vite/React SPA — every cited path resolving (<strong>42 of 42</strong>), and ends
in a table mapping each <code class="language-plaintext highlighter-rouge">apps/qualia-console</code> decision to the source that produced it. The crate then
shipped as one egui/eframe binary with <strong>five</strong> views, <strong>six</strong> snapshot tests written for the empty
and error cases first, and <strong>16</strong> tests total, with no <code class="language-plaintext highlighter-rouge">192.168.</code> literal in <code class="language-plaintext highlighter-rouge">src/</code>. It was smoke-run
for real: against a live shared region and a stub <code class="language-plaintext highlighter-rouge">GET /braid</code>, all five views were read back through
the window’s accessibility tree — belief layers <code class="language-plaintext highlighter-rouge">live</code> at 443 ms, pose <code class="language-plaintext highlighter-rouge">x 1.250 m, z -0.500 m,
yaw 0.300 rad, confidence 0.88</code>, map <code class="language-plaintext highlighter-rouge">512 x 512 cells at 0.050 m/cell</code>. The TUI gained a Mission panel
and the line <code class="language-plaintext highlighter-rouge">braid gen {n} · belief lag: {ms} ms</code>, and <code class="language-plaintext highlighter-rouge">grep -rn QUALIA_OPS_URL</code> returns nothing. As a
GUI it is host-only by definition: the board is headless, so its aarch64 artifact is the board
evidence.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-front-end-rebuilt-from-lessons/hero.webp" width="1100" height="619" alt="The extruded psi monogram beside five staggered extruded tiles, one per view the console opens, in the order the crate declares them: mission, belief, world, evidence, telemetry." />
  </picture>
  <figcaption>
    <p>The extruded mark beside the console's five views as five staggered extruded tiles, in
    <code>VIEWS</code> order — mission, belief, world, evidence, telemetry: the five floating windows
    the console opens.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>The lessons document ran before the crate, deliberately.</strong> Step 25 exists so that
<code class="language-plaintext highlighter-rouge">apps/qualia-console</code> is built <em>against evidence</em>. Its five sections use a fixed form — what it does →
keep → avoid → evidence (path) — and the closing table is the contract. Two of the five sources are
in a private repository read-only clone; nothing was copied, and the document records lessons and
paths only. <code class="language-plaintext highlighter-rouge">docs/inspiration.md</code> indexes every private path that was read. <code class="language-plaintext highlighter-rouge">runners/ops</code> is written
up as a lesson and not as a component, because Step 27 deletes it and this repository never carried
it.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-front-end-rebuilt-from-lessons/lesson-sources.svg" width="1100" height="494" alt="How many of the console's decisions each of the five front ends that docs/frontend-lessons.md read informs, counted from the document's closing Comes from column, with the most-named source picked out." />
  </picture>
  <figcaption>
    <p>How many of the console's decisions each of the five front ends that
    <code>docs/frontend-lessons.md</code> read informs, counted from the document's closing
    "Comes from" column; the most-named source is picked out. The lessons document is the entry's
    substance — this is the route to it.</p>
  </figcaption>
</figure>

<p><strong>The stacked top headers were built, then thrown away.</strong> The first console had a top bar, a tab row
and per-view headers; the operator’s direction replaced them with five floating, movable, resizable
<code class="language-plaintext highlighter-rouge">egui::Window</code>s staggered on a diagonal, one slim strip, and a menu to re-open a closed window. The
recovered work was finished as one commit and the blockers as another, so the change of direction is
visible in history rather than hidden in a squash.</p>

<p><strong>A manifest edit was reverted after review.</strong> The console briefly declared <code class="language-plaintext highlighter-rouge">qualia-lidar</code>,
<code class="language-plaintext highlighter-rouge">qualia-camera</code> and <code class="language-plaintext highlighter-rouge">qualia-vslam</code> into <code class="language-plaintext highlighter-rouge">config/stack-manifest.default.json</code>; the contract re-read
ruled it out of scope, the file went back byte-identical to the merge base, and the Telemetry view
instead derives its rows from the ABI slots — a named stack contributes its sensing runners in its
own order, and no stack renders the honest empty table. Two tests pin that route.</p>

<p><strong>Small correctness fixes kept, one dead field deleted.</strong> The Refresh button was inert; the telemetry
view dropped a row on a torn read and rendered a never-published camera as zeros; the poll loop
re-inventoried every <code class="language-plaintext highlighter-rouge">*.mcap</code> four times a second; the dead <code class="language-plaintext highlighter-rouge">SegmentReading::sha256</code> field and the
fixture-shaped <code class="language-plaintext highlighter-rouge">Sample::healthy</code> builder were removed from the library (the builder moved to
<code class="language-plaintext highlighter-rouge">tests/support/</code>). A README toolchain note claiming a <code class="language-plaintext highlighter-rouge">Cargo.lock</code> pin the lock did not carry was
deleted rather than corrected.</p>

<p><strong>The board leg blocked rather than faked.</strong> The dev host has no Docker engine, no <code class="language-plaintext highlighter-rouge">cross</code>, and no
aarch64 C toolchain: <code class="language-plaintext highlighter-rouge">cargo check --target aarch64-unknown-linux-gnu -p qualia-console</code> walks 91
dependency crates and dies in <code class="language-plaintext highlighter-rouge">ring</code>’s build script for want of <code class="language-plaintext highlighter-rouge">aarch64-linux-gnu-gcc</code>. That was
recorded as <strong>blocked</strong>, not as a build. The console was then built natively on Pinkie instead
(D-010/D-018).</p>

<h2 id="five-views-one-enum-and-a-fixture-that-needs-no-stack">Five views, one enum, and a fixture that needs no stack</h2>

<p>The view set is fixed — mission, belief, world, evidence, telemetry — one module each under
<code class="language-plaintext highlighter-rouge">src/views/</code>, and the agent’s base URL comes from <code class="language-plaintext highlighter-rouge">QUALIA_AGENT_URL</code> (default
<code class="language-plaintext highlighter-rouge">http://127.0.0.1:8080</code>) with no host literal in the source. The snapshots are
<code class="language-plaintext highlighter-rouge">mission_healthy</code>, <code class="language-plaintext highlighter-rouge">mission_degraded</code>, <code class="language-plaintext highlighter-rouge">belief_stale</code>, <code class="language-plaintext highlighter-rouge">evidence_empty</code>, <code class="language-plaintext highlighter-rouge">world_fresh</code> and
<code class="language-plaintext highlighter-rouge">default_arrangement</code>, all driven from one committed <code class="language-plaintext highlighter-rouge">braid-state.json</code> fixture — <code class="language-plaintext highlighter-rouge">world_fresh</code>
attaches a fresh region of its own — so no live stack is needed; the empty and error cases were
written first because those are the ones that regress.</p>

<p>The TUI half is the same data on a terminal: <code class="language-plaintext highlighter-rouge">runners/watch</code> gained a Mission panel reading
<code class="language-plaintext highlighter-rouge">GET /braid</code> and the chrome line <code class="language-plaintext highlighter-rouge">braid gen {n} · belief lag: {ms} ms</code>, with the milliseconds from
<code class="language-plaintext highlighter-rouge">BeliefClock::decision_latency_ns()</code>. The existing panels and child supervision are unchanged, and the
ops dashboard’s carriers are gone: <code class="language-plaintext highlighter-rouge">grep -rn QUALIA_OPS_URL</code> returns nothing, and <code class="language-plaintext highlighter-rouge">runners/ops</code> was
never in <code class="language-plaintext highlighter-rouge">git ls-tree origin/main runners/</code> to delete. <code class="language-plaintext highlighter-rouge">qualia-watch</code> reached <strong>38 passed / 0 failed</strong>
on the board, up from 36, the two extra tests being the agent-URL scheme fix.</p>

<h2 id="the-board-can-build-it-not-display-it">The board can build it, not display it</h2>

<table>
  <thead>
    <tr>
      <th>Artifact</th>
      <th style="text-align: right">Size</th>
      <th>SHA-256 (first 8)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-console</code> aarch64 (Pinkie)</td>
      <td style="text-align: right">317,755,264 B</td>
      <td><code class="language-plaintext highlighter-rouge">f02168cc</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-watch</code> aarch64 (Pinkie)</td>
      <td style="text-align: right">72,617,480 B</td>
      <td><code class="language-plaintext highlighter-rouge">48aceef9</code></td>
    </tr>
  </tbody>
</table>

<p>Pinkie has <code class="language-plaintext highlighter-rouge">DISPLAY</code>/<code class="language-plaintext highlighter-rouge">WAYLAND_DISPLAY</code> unset, <code class="language-plaintext highlighter-rouge">XDG_SESSION_TYPE=tty</code> and no compositor, so an egui
window cannot open there; the built ELF is the board evidence and the interactive smoke stays the
host record. The watch binary is different: under a PTY with <code class="language-plaintext highlighter-rouge">stty rows 40 cols 130</code> it enters the
alternate screen and draws the tab row through <code class="language-plaintext highlighter-rouge">8:Mission</code>; operator input cannot be exercised
headlessly, so the panel rendering is covered by <code class="language-plaintext highlighter-rouge">tests/view.rs</code> and <code class="language-plaintext highlighter-rouge">tests/braid.rs</code> instead.</p>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sources read for the lessons doc</td>
      <td style="text-align: right">5</td>
      <td>front ends</td>
      <td><code class="language-plaintext highlighter-rouge">docs/frontend-lessons.md</code></td>
    </tr>
    <tr>
      <td>Cited paths that resolve</td>
      <td style="text-align: right">42 of 42</td>
      <td>paths</td>
      <td>PR #119 body ^1</td>
    </tr>
    <tr>
      <td>Console views</td>
      <td style="text-align: right">5</td>
      <td>views</td>
      <td><code class="language-plaintext highlighter-rouge">apps/qualia-console/src/views/</code></td>
    </tr>
    <tr>
      <td>Committed snapshots</td>
      <td style="text-align: right">6</td>
      <td>snapshots</td>
      <td><code class="language-plaintext highlighter-rouge">tests/snapshots.rs</code></td>
    </tr>
    <tr>
      <td>Console tests</td>
      <td style="text-align: right">16 passed / 0 failed</td>
      <td>tests</td>
      <td>T26 comment ^2</td>
    </tr>
    <tr>
      <td>Console aarch64 artifact</td>
      <td style="text-align: right">317,755,264</td>
      <td>bytes</td>
      <td>Board2/Board3 comments, PR #152 ^2</td>
    </tr>
    <tr>
      <td>Console artifact SHA-256</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">f02168cc…</code></td>
      <td>—</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Belief layers read back in the smoke</td>
      <td style="text-align: right">443</td>
      <td>ms age</td>
      <td>T26 comment ^2</td>
    </tr>
    <tr>
      <td>Pose read back</td>
      <td style="text-align: right">x 1.250, z -0.500, yaw 0.300, conf 0.88</td>
      <td>m, m, rad, —</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Map read back</td>
      <td style="text-align: right">512 × 512 at 0.050</td>
      <td>cells, m/cell</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-watch</code> board tests</td>
      <td style="text-align: right">38 passed / 0 failed</td>
      <td>tests</td>
      <td>Board3 comment, PR #191 ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">qualia-watch</code> aarch64 artifact</td>
      <td style="text-align: right">72,617,480</td>
      <td>bytes</td>
      <td>same ^2</td>
    </tr>
  </tbody>
</table>

<p>^1 The 42/42 path resolution was checked when the document landed, in the session that wrote it.
^2 The smoke readings and the board builds are from different sessions: the console smoke was taken by
the session that recovered the crashed worktree, and the Pinkie artifacts by the board job. The two
board artifacts were built in different legs, and the console’s was reproduced byte-for-byte by a
second leg.</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/665c1ab...7ad59a1"><code class="language-plaintext highlighter-rouge">665c1ab..7ad59a1</code></a>: the lessons commit through the merge that carried the TUI change (T27, PR #191, merged 2026-09-11T18:15:39Z). The range has to end there, not at the TUI change’s board leg <code class="language-plaintext highlighter-rouge">2306c4c</code>: the console (T26, PR #152, merge <code class="language-plaintext highlighter-rouge">4700e47</code>) is not an ancestor of <code class="language-plaintext highlighter-rouge">2306c4c</code> — <code class="language-plaintext highlighter-rouge">git merge-base --is-ancestor 4700e47 2306c4c</code> fails — while <code class="language-plaintext highlighter-rouge">7ad59a1</code> contains both. The console’s five views, its 16-test host run and its aarch64 board
artifacts describe the range’s endpoint, where <code class="language-plaintext highlighter-rouge">VIEWS</code> is <code class="language-plaintext highlighter-rouge">[View; 5]</code>; at <code class="language-plaintext highlighter-rouge">main</code> it is <code class="language-plaintext highlighter-rouge">[View; 6]</code> because T51 added <code class="language-plaintext highlighter-rouge">View::Brain</code> (<code class="language-plaintext highlighter-rouge">a65f94f</code>, PR #201, merged 2026-09-11T19:55:40Z) after this entry’s period. Its epic is <a href="https://github.com/superposition/qualia/issues/10">EPIC-09 (#10)</a>;
tickets <a href="https://github.com/superposition/qualia/issues/41">T25 #41</a>,
<a href="https://github.com/superposition/qualia/issues/42">T26 #42</a>,
<a href="https://github.com/superposition/qualia/issues/43">T27 #43</a>.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>The smoke is one session’s reading.</strong> The pose, map, ledger and telemetry values above are quoted
from a smoke run against a real shared region and a stub <code class="language-plaintext highlighter-rouge">GET /braid</code> — not a live agent, not Leash.
The accessibility-tree read-back is the method; there is no automated end-to-end test of the window.</li>
  <li><strong>The GUI has never run on the board, and cannot.</strong> Headless is a property of the machine, not a
configuration gap; the aarch64 build is the only board evidence.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">docs/frontend-lessons.md</code> is the entry’s substance, not this post.</strong> Five sources distilled into
a table is a document; whether a reader of <em>this</em> entry learns the same lessons depends on following
the link.</li>
  <li><strong>The TUI’s Mission panel was not exercised by a human on the board.</strong> Rendering is covered by tests
and a PTY start; selecting the tab and scrolling were not driven.</li>
  <li><strong>The 42/42 path check is a point-in-time check.</strong> Paths in a private repository can move; nothing
re-runs the resolution.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="frontend" /><category term="egui" /><category term="tui" /><category term="testing" /><summary type="html"><![CDATA[Five existing front ends read as evidence, the lessons written down before the crate existed, then one egui binary with five views, six snapshot tests and a screen that was actually read back — plus a TUI panel and a headless board that can build the GUI but not display it.]]></summary></entry><entry><title type="html">The fly in the belief matrices</title><link href="https://superposition.github.io/journal/the-fly-in-the-belief-matrices/" rel="alternate" type="text/html" title="The fly in the belief matrices" /><published>2026-09-11T16:40:00-04:00</published><updated>2026-09-11T16:40:00-04:00</updated><id>https://superposition.github.io/journal/the-fly-in-the-belief-matrices</id><content type="html" xml:base="https://superposition.github.io/journal/the-fly-in-the-belief-matrices/"><![CDATA[<p><strong>The claim.</strong> The prior is now a number in the belief loop and a number on the GPU, and neither
number can move a motor. <code class="language-plaintext highlighter-rouge">CouplingPrior::load</code> verifies the producer’s three section digests — and the
size the counts imply — before it decodes anything; <code class="language-plaintext highlighter-rouge">couple</code> scales each mapped belief slot by its
type’s in-strength — the summed weight of that type’s incoming edges — normalised by the peak, and
returns the total applied. On the 4090, with a fixture whose in-strengths are 4, 8 and 2, that total
printed <strong><code class="language-plaintext highlighter-rouge">fly prior: applied 1.75</code> once per tick</strong> (0.5 + 1.0 + 0.25), 162 lines in about 5 s — and
the arithmetic is normalised, so the value is a weight, not a count. Behind it: the flag <code class="language-plaintext highlighter-rouge">fly-prior</code>, <strong>off by default</strong>, under which both backends
return <code class="language-plaintext highlighter-rouge">Ok(0.0)</code> for every input; an invented rate model in a separate crate behind a second
off-by-default feature; and three new kernels measured on the 4090 at <strong>2.50 µs</strong> (<code class="language-plaintext highlighter-rouge">belief_couple</code>,
1 × 4), <strong>10.59 µs</strong> (<code class="language-plaintext highlighter-rouge">action_score</code>, 2 × 256) and <strong>11.84 µs</strong> (<code class="language-plaintext highlighter-rouge">perception_voxel</code>, 48 × 256).</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-fly-in-the-belief-matrices/prior-path.svg" width="1100" height="830" alt="The connectome artifact's path into the belief slots: dataset to committed graph.bin and manifest.json, a digest-checked load, peak-normalised in-strength, couple(belief, slots), and the layer belief; the off-by-default fly-prior flag, the refusal on an unmappable mapping, and the coupling's host-side, no-kernel nature are called out beside the path." />
  </picture>
  <figcaption>
    <p>The connectome artifact's path into the belief slots: dataset → committed
    <code>graph.bin</code>/<code>manifest.json</code> → digest-checked load → peak-normalised
    in-strength → <code>couple(belief, slots)</code> → the layer belief, with the off-by-default
    <code>fly-prior</code> flag, the refusal on an unmappable mapping, and the coupling's host-side
    (no-kernel) nature called out.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>A signature that could not work on one of the two backends was changed, and said so.</strong> The plan’s
step 11 gives Metal the same <code class="language-plaintext highlighter-rouge">couple_prior(ctx, prior, slots)</code>. <code class="language-plaintext highlighter-rouge">MetalContext</code> is macOS-only, the
coupling is host-side data (D-001), and the Metal belief loop holds no <code class="language-plaintext highlighter-rouge">MetalCognitionStack</code> — building
one to pass it here would allocate and initialise the whole layer set for a host-side sum. The shipped
Metal signature is <code class="language-plaintext highlighter-rouge">couple_prior(prior, slots)</code>, same name, same feature, no context.</p>

<p><strong>The per-tick call moved out of the runner.</strong> Step 12 puts <code class="language-plaintext highlighter-rouge">couple_prior</code> in each belief runner’s
<code class="language-plaintext highlighter-rouge">src/main.rs</code>; those are pure dispatchers, and <code class="language-plaintext highlighter-rouge">runners/l3-belief</code>’s own test pins that the runner must
not touch the layer slot. The mode, the prior load and the diagnostics stay in the runners; the
per-tick coupling is wired where the loop is, in the compute backends, behind the same feature. The
reference tree has no <code class="language-plaintext highlighter-rouge">QUALIA_FLY_*</code> and no coupling, so no reference behaviour could decide this; the
plan’s intent — a per-tick coupled belief under <code class="language-plaintext highlighter-rouge">QUALIA_FLY_MODE</code> — could not be reached from a
dispatcher.</p>

<p><strong>A stacked PR stranded a ticket, and it was replayed rather than re-invented.</strong> <code class="language-plaintext highlighter-rouge">#27</code> (T12) was
opened with base <code class="language-plaintext highlighter-rouge">ticket/T11</code> and merged into that branch; when <code class="language-plaintext highlighter-rouge">ticket/T11</code> was later rebased onto
<code class="language-plaintext highlighter-rouge">main</code>, the rebase dropped the merge commit and with it T12’s commits, so the work was an ancestor of
neither. That is now decision D-019, and the replay (<code class="language-plaintext highlighter-rouge">ticket/T12-replay</code>, PR #198) is a single
<code class="language-plaintext highlighter-rouge">cherry-pick -x</code> of the reviewed commit. It was open when this entry was written and merged on
2026-09-11T19:55:37Z in <code class="language-plaintext highlighter-rouge">14b60de</code> (PR #198).</p>

<p><strong>The simulator was kept away from the motor path by construction.</strong> The dataset carries no dynamics
and no sign; the model is invented. So it is a separate crate (<code class="language-plaintext highlighter-rouge">qualia-fly-circuit</code>, feature <code class="language-plaintext highlighter-rouge">sim</code>
off by default) whose README says in one paragraph that it is a rate model over a graph, not a
connectome simulation; its weights are used as positive because the artifact carries no sign; and a
build without the feature compiles an empty crate with no dependencies.</p>

<h2 id="coupling-is-a-normalisation-and-the-observable-is-the-total">Coupling is a normalisation, and the observable is the total</h2>

\[\text{applied} \;=\; \sum_{i \in \text{slots}} \frac{\text{strength}(type_i)}{\max_j \text{strength}(type_j)}\]

<p>Two consequences are worth separating. First, the value is bounded by the slot count and reaches 1.0
only for a uniformly innervated graph — the same property that later made a naive “sum, then clamp to
0..1” reading a de-facto boolean, so the exploration ticket divides by the coupled-type count (the
mean applied weight) instead. Second, the prior cannot silently half-apply: a mapping the graph or
the layer cannot satisfy is refused with <code class="language-plaintext highlighter-rouge">UnknownType(u32)</code> or <code class="language-plaintext highlighter-rouge">SlotOutOfRange(usize)</code>, not skipped,
so a stale mapping cannot read as a partial success. With the feature off, the symbol exists and
returns <code class="language-plaintext highlighter-rouge">Ok(0.0)</code>; there is no branch in the belief loop.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-fly-in-the-belief-matrices/coupling-normalisation.svg" width="1100" height="497" alt="Two panels of the factor CouplingPrior::couple applies per belief type, with the peak type in blue: left, the tests' three-type fixture (in-strength 4, 8, 2 giving 0.5, 1.0, 0.25, applied 1.75); right, the committed five-type artifact (in-strength 19, 3, 33, 12, 25, peak 33, applied 2.7879, mean 0.5576)." />
  </picture>
  <figcaption>
    <p>The factor <code>CouplingPrior::couple</code> applies to a mapped belief slot, per type:
    left, the tests' three-type fixture (in-strength 4, 8, 2 → 0.5, 1.0, 0.25, applied 1.75);
    right, the committed five-type artifact (in-strength 19, 3, 33, 12, 25, peak 33, applied
    2.7879, mean 0.5576). The blue bar is the peak type, which couples at unit weight.</p>
  </figcaption>
</figure>

<p>The honest limit, recorded on the ticket: on an idle stack the coupling’s effect on the <em>published</em>
belief is not separately observable — the belief starts at zero and the identity model keeps it there,
and the coupling scales the mean. The observable is the per-tick total above plus the unit test that
pins the normalised scaling.</p>

<h2 id="the-board-and-the-gpu">The board and the GPU</h2>

<p>Two independent exercises, and they measured different things.</p>

<p><strong>The Orin NX (aarch64).</strong> <code class="language-plaintext highlighter-rouge">qualia-cuda --features fly-prior</code> → <strong>29 passed / 0 failed</strong>, including
<code class="language-plaintext highlighter-rouge">coupling_applies_the_prior_by_type_strength</code> and <code class="language-plaintext highlighter-rouge">coupling_refuses_an_unmappable_slot</code>;
<code class="language-plaintext highlighter-rouge">qualia-metal --features fly-prior</code> → <strong>15 passed</strong> (the platform-independent CPU fallback; no Metal
device is claimed on Linux). The coupling tests opened a real <code class="language-plaintext highlighter-rouge">CudaContext</code> — no <code class="language-plaintext highlighter-rouge">skipping</code> line — and
the artifact was an ELF aarch64 binary. The <code class="language-plaintext highlighter-rouge">FlySimSlot</code> half landed separately on the board:
<code class="language-plaintext highlighter-rouge">qualia-jepa-runtime --features sim</code> → <strong>8 passed</strong> plus 2 smoke tests, with
<code class="language-plaintext highlighter-rouge">fly_sim_publishes_only_while_observe_only_is_approved</code> publishing <code class="language-plaintext highlighter-rouge">sim_step</code> 1 then 2 into
<code class="language-plaintext highlighter-rouge">SHM_VERSION</code> 3’s slot, and a smoke start that printed <code class="language-plaintext highlighter-rouge">fly sim: disabled (QUALIA_FLY_PRIOR_PATH is
unset)</code>.</p>

<p><strong>The 4090.</strong> The three new kernels ran once each in a single-threaded capture under Nsight Systems
(WSL2 host, <code class="language-plaintext highlighter-rouge">nsys 2025.3.2.474</code>, <code class="language-plaintext highlighter-rouge">mage 0.1.0</code>): 16 launches over 8 kernels, <strong>4892.89 µs</strong> of kernel
time, of which the new three are 2.50 µs (<code class="language-plaintext highlighter-rouge">belief_couple</code>), 10.59 µs (<code class="language-plaintext highlighter-rouge">action_score</code>) and 11.84 µs
(<code class="language-plaintext highlighter-rouge">perception_voxel</code>). That capture is committed under <code class="language-plaintext highlighter-rouge">docs/evidence/T16/three-kernels/</code> and is the
number T17 and T18 have to beat. It replaced a 5-kernel baseline of <strong>4784.75 µs</strong> / 13 launches
(<code class="language-plaintext highlighter-rouge">docs/evidence/baseline-2026-09-11/</code>, at <code class="language-plaintext highlighter-rouge">76143f0</code>).</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-fly-in-the-belief-matrices/new-kernels.svg" width="1100" height="527" alt="The T16 capture's per-kernel time on the RTX 4090 on a log axis: 16 launches over 8 kernels, 4892.893 microseconds, with the three kernels this epic added (belief_couple 2.496, action_score 10.592, perception_voxel 11.84 microseconds) against the 13-launch, 4784.753-microsecond baseline they replaced." />
  </picture>
  <figcaption>
    <p>The T16 capture's per-kernel time on the RTX 4090 (log axis): 16 launches over 8 kernels,
    4892.893 µs, of which the three kernels this epic added (<code>belief_couple</code> 2.50,
    <code>action_score</code> 10.59, <code>perception_voxel</code> 11.84 µs) are 24.928 µs, against
    the 13-launch, 4784.753 µs baseline they replaced.</p>
  </figcaption>
</figure>

<p>The ABI for the simulator’s slot is fully pinned: <code class="language-plaintext highlighter-rouge">FlySimPayload</code> is <code class="language-plaintext highlighter-rouge">repr(C, align(64))</code>, 65,984
bytes, with a 65,536-byte state array (<code class="language-plaintext highlighter-rouge">FLY_SIM_MAX_TYPES</code> = 16,384 <code class="language-plaintext highlighter-rouge">f32</code>) and <code class="language-plaintext highlighter-rouge">SHM_VERSION</code> bumped
2 → 3. The payload carries no coupling gain — the model keeps <code class="language-plaintext highlighter-rouge">gain</code> private, so an observer cannot
be handed a value the writer cannot read.</p>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Fixture coupling total per tick</td>
      <td style="text-align: right">1.75</td>
      <td>weight</td>
      <td>T12 comment (RTX 4090 smoke) ^1</td>
    </tr>
    <tr>
      <td>Fixture in-strengths</td>
      <td style="text-align: right">4, 8, 2 (peak 8)</td>
      <td>weight</td>
      <td>T12 comment ^1</td>
    </tr>
    <tr>
      <td>cuda <code class="language-plaintext highlighter-rouge">fly-prior</code> tests on Pinkie</td>
      <td style="text-align: right">29 passed / 0 failed</td>
      <td>tests</td>
      <td>Board3 comment, PR #190</td>
    </tr>
    <tr>
      <td>metal <code class="language-plaintext highlighter-rouge">fly-prior</code> tests on Pinkie</td>
      <td style="text-align: right">15 passed / 0 failed</td>
      <td>tests</td>
      <td>same</td>
    </tr>
    <tr>
      <td>jepa-runtime <code class="language-plaintext highlighter-rouge">sim</code> tests on Pinkie</td>
      <td style="text-align: right">8 + 2 passed</td>
      <td>tests</td>
      <td>Board3 comment, PR #189</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">FlySimPayload</code> size</td>
      <td style="text-align: right">65,984</td>
      <td>bytes</td>
      <td>T15 ABI table</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">FLY_SIM_MAX_TYPES</code></td>
      <td style="text-align: right">16,384</td>
      <td>types</td>
      <td>T15 ABI table</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SHM_VERSION</code> after T15</td>
      <td style="text-align: right">3</td>
      <td>version</td>
      <td>T15 comment</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">belief_couple</code> on 4090</td>
      <td style="text-align: right">2.50</td>
      <td>µs/launch</td>
      <td><code class="language-plaintext highlighter-rouge">docs/evidence/T16/three-kernels/README.md</code> ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">action_score</code> on 4090</td>
      <td style="text-align: right">10.59</td>
      <td>µs/launch</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">perception_voxel</code> on 4090</td>
      <td style="text-align: right">11.84</td>
      <td>µs/launch</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Capture total (8 kernels)</td>
      <td style="text-align: right">4892.89</td>
      <td>µs</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Prior capture total (5 kernels)</td>
      <td style="text-align: right">4784.75</td>
      <td>µs</td>
      <td><code class="language-plaintext highlighter-rouge">docs/evidence/baseline-2026-09-11/README.md</code> ^2</td>
    </tr>
  </tbody>
</table>

<p>^1 Measured on the host’s RTX 4090 in a different session from the board runs; the value is the
fixture prior’s total, not a dataset-scale coupling.
^2 Both captures are from different sessions and different hardware: the T16 capture is the RTX 4090
under <code class="language-plaintext highlighter-rouge">nsys</code> on WSL2; the baseline is the same host before the three kernels existed. Durations on a
shared 4090 are one contended sample; launch count and shape are the stable part.</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/5999ba4...b13ca80"><code class="language-plaintext highlighter-rouge">5999ba4..b13ca80</code></a> — the first coupling commit through the
merge that put the backend <code class="language-plaintext highlighter-rouge">couple_prior</code> on <code class="language-plaintext highlighter-rouge">main</code>. Epics:
<a href="https://github.com/superposition/qualia/issues/4">EPIC-04 (#4)</a>,
<a href="https://github.com/superposition/qualia/issues/5">EPIC-05 (#5)</a>,
<a href="https://github.com/superposition/qualia/issues/6">EPIC-06 (#6)</a>.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>T17 has not landed; T18 landed after this entry’s period.</strong> CPU/CUDA parity for the three new
kernels was <code class="language-plaintext highlighter-rouge">status:ready</code> (<code class="language-plaintext highlighter-rouge">#32</code>) and was <code class="language-plaintext highlighter-rouge">status:review</code> as of 2026-09-11T20:45Z (<code class="language-plaintext highlighter-rouge">#32</code>, open):
the three kernels have host oracles and a capture, not a parity assertion. The ≤ 6 GiB memory plan
and the <code class="language-plaintext highlighter-rouge">sm_87</code>/<code class="language-plaintext highlighter-rouge">sm_89</code> fatbin targets were <code class="language-plaintext highlighter-rouge">status:ready</code> (<code class="language-plaintext highlighter-rouge">#33</code>); T18 landed in <code class="language-plaintext highlighter-rouge">60beee4</code> (PR #207,
merged 2026-09-11T20:16:14Z), and its board capture shows the sm_87 cubins loading on Pinkie with no
<code class="language-plaintext highlighter-rouge">CUDA_ERROR_UNSUPPORTED_PTX_VERSION</code> (<code class="language-plaintext highlighter-rouge">docs/evidence/T18/fatbin-sm-87/</code>).</li>
  <li><strong>T12 was not on <code class="language-plaintext highlighter-rouge">main</code> when this entry was written.</strong> The runner wiring that reads
<code class="language-plaintext highlighter-rouge">QUALIA_FLY_MODE</code> and loads the prior at start-up was the replay on PR #198, then still open; it
merged in <code class="language-plaintext highlighter-rouge">14b60de</code> (2026-09-11T19:55:37Z). At the entry’s endpoint, <code class="language-plaintext highlighter-rouge">main</code> carried the backend
coupling, the manifests’ env keys and the tests.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">semantic_novelty</code> and dimorphism are not derivable.</strong> The artifact aggregates dimorphism away and
the runtime carries no cell-to-type map; the exploration ticket sends a documented <code class="language-plaintext highlighter-rouge">0.0</code>.</li>
  <li><strong>The simulator has no drive.</strong> Nothing in the JEPA path is an input to the type graph, so the
published state is the model’s resting state with a zeros drive — stated in the code, not hidden.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">couple</code>’s effect on published belief is unobserved on an idle stack</strong> (see above). The per-tick
total and the unit tests are the evidence; a mission that moves the belief has not been run.</li>
  <li><strong>The 4090 numbers are one contended session.</strong> No error bar and no repeated-run spread are
recorded in the T16 capture; compare shape and launch count first.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="connectome" /><category term="cuda" /><category term="coupling" /><category term="belief" /><summary type="html"><![CDATA[A connectome prior loaded, digest-checked, coupled into the belief layers behind an off-by-default feature, and watching its own rate model publish observe-only — seven tickets, a 1.75 coupling total on the 4090, and three CUDA kernels measured at 2.50, 10.59 and 11.84 µs.]]></summary></entry><entry><title type="html">The connectome as a prior</title><link href="https://superposition.github.io/journal/the-connectome-as-a-prior/" rel="alternate" type="text/html" title="The connectome as a prior" /><published>2026-09-11T16:35:00-04:00</published><updated>2026-09-11T16:35:00-04:00</updated><id>https://superposition.github.io/journal/the-connectome-as-a-prior</id><content type="html" xml:base="https://superposition.github.io/journal/the-connectome-as-a-prior/"><![CDATA[<p><strong>The claim.</strong> A connectome becomes usable as a prior at exactly one moment: when it is written down
as a file whose numbers a consumer can verify. This step builds the type-level graph <strong>offline</strong>, from
two Feather tables, and emits three files: <code class="language-plaintext highlighter-rouge">graph.bin</code> (<code class="language-plaintext highlighter-rouge">rowptr</code> <code class="language-plaintext highlighter-rouge">u64</code>, then <code class="language-plaintext highlighter-rouge">cols</code> <code class="language-plaintext highlighter-rouge">u32</code>, then
<code class="language-plaintext highlighter-rouge">weights</code> <code class="language-plaintext highlighter-rouge">u32</code>, little-endian — a compressed sparse row (CSR), in which <code class="language-plaintext highlighter-rouge">rowptr</code> gives each type’s
slice of the concatenated <code class="language-plaintext highlighter-rouge">cols</code> and <code class="language-plaintext highlighter-rouge">weights</code>), <code class="language-plaintext highlighter-rouge">manifest.json</code> (schema <code class="language-plaintext highlighter-rouge">qualia.connectome-prior.v1</code>,
a type count, an edge count,
four SHA-256 digests and the attribution) and <code class="language-plaintext highlighter-rouge">attribution.json</code>
(<code class="language-plaintext highlighter-rouge">male-cns:v1.0</code>, <code class="language-plaintext highlighter-rouge">CC-BY-4.0</code>, the dataset URL, <code class="language-plaintext highlighter-rouge">Berg et al. 2026, Cell</code>). It was exercised on a
hand-written fixture of <strong>12 edges over 5 types</strong>, which collapse to <strong>9</strong> distinct type pairs and to
a CSR of <code class="language-plaintext highlighter-rouge">rowptr = [0,2,4,5,7,9]</code>, <code class="language-plaintext highlighter-rouge">cols = [1,2,2,4,0,0,2,2,3]</code>,
<code class="language-plaintext highlighter-rouge">weights = [3,2,8,25,13,6,11,12,12]</code>, with <strong>7 tests</strong> passing. The same builder, pointed at the real
release, is the one that would produce the <strong>929,735-edge</strong> type graph over <strong>11,687 types</strong> the
earlier entry measured from the dataset. Nothing here downloaded the dataset; the fixture is the
whole measured claim.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-connectome-as-a-prior/hero.webp" width="1100" height="619" alt="The extruded psi monogram beside a five-by-five lattice of raised blocks: one block for each of the nine nonzero (pre_type, post_type) pairs of the committed fixture, its height the pair's summed weight." />
  </picture>
  <figcaption>
    <p>The extruded mark beside the fixture's type-level CSR: nine raised blocks on the 5×5 type
    lattice, one per nonzero <code>(pre_type, post_type)</code> pair, each block's height the pair's
    summed weight. The other sixteen cells are the absent pairs.</p>
  </figcaption>
</figure>

<h2 id="what-we-tried">What we tried</h2>

<p><strong>A single crate, four narrow steps.</strong> <code class="language-plaintext highlighter-rouge">build_type_graph</code> reads Arrow IPC (file and stream framing),
maps both endpoints through the annotation table, sums weights per <code class="language-plaintext highlighter-rouge">(pre_type, post_type)</code>, sorts by
that pair and emits CSR. <code class="language-plaintext highlighter-rouge">write_prior</code> writes the three files. <code class="language-plaintext highlighter-rouge">main.rs</code> is a clap binary with three
arguments. The last step added the error paths. They landed as four commits — <code class="language-plaintext highlighter-rouge">b56789e</code>, <code class="language-plaintext highlighter-rouge">a61fdb9</code>,
<code class="language-plaintext highlighter-rouge">6799365</code>, <code class="language-plaintext highlighter-rouge">8adb09c</code> on <code class="language-plaintext highlighter-rouge">ticket/T06</code> — because one owner held the directory and the tests could grow
one assertion at a time.</p>

<p><strong>The plan’s Arrow 53 was abandoned.</strong> <code class="language-plaintext highlighter-rouge">arrow = "53"</code> cannot compile in this workspace: <code class="language-plaintext highlighter-rouge">arrow-arith</code>
53.4.0 declares an internal <code class="language-plaintext highlighter-rouge">ChronoDateExt::quarter()</code> that collides with <code class="language-plaintext highlighter-rouge">chrono::Datelike::quarter</code>,
added in chrono 0.4.44. Arrow 56 is already the workspace’s arrow (through <code class="language-plaintext highlighter-rouge">rerun</code>), removed the
redundant methods, and carries the same IPC reader. The dependency is <code class="language-plaintext highlighter-rouge">arrow = { version = "56",
features = ["ipc"] }</code>, and the lock churn is exactly the arrow 53 stack leaving (14 packages) plus
<code class="language-plaintext highlighter-rouge">arrow-csv 56.2.1</code>. The ticket text was left as written; this is the resolution.</p>

<p><strong>The binary was rebuilt three times for line endings.</strong> <code class="language-plaintext highlighter-rouge">860235a</code> → <code class="language-plaintext highlighter-rouge">b56789e</code>, <code class="language-plaintext highlighter-rouge">d4eff4c</code> →
<code class="language-plaintext highlighter-rouge">a61fdb9</code>, <code class="language-plaintext highlighter-rouge">d670f93</code> → <code class="language-plaintext highlighter-rouge">6799365</code>: a staging script had introduced CRLF into the new files, and the
provenance gate treats line-ending differences as real (see <a href="https://superposition.github.io/journal/the-licence-and-the-snapshot/">the licence
entry</a>). Content unchanged
each time; the LF rewrite was cheaper than teaching the gate an exception.</p>

<p><strong><code class="language-plaintext highlighter-rouge">edge_count</code> had two defensible readings and we fixed one.</strong> The manifest says <code class="language-plaintext highlighter-rouge">edge_count</code>, and
<code class="language-plaintext highlighter-rouge">write_prior</code> receives only the graph, so the only value recoverable from its inputs is the CSR
nonzero count — the 12 fixture rows collapse to 9 pairs and the manifest records <code class="language-plaintext highlighter-rouge">9</code>. The alternative
(segment-level rows) is not available to the function, so the ambiguity was resolved by the interface,
and stated on the ticket rather than left to a reader.</p>

<h2 id="the-fixture-is-the-oracle">The fixture is the oracle</h2>

<p>The test does not assert against a table copied from the implementation. It synthesises Feather inputs
from the committed CSVs with arrow’s own IPC writer, then aggregates an oracle <strong>in the test</strong> from
the CSV rows, and compares the emitted CSR to that. The invariant the fixture holds is the one the
builder needs: every <code class="language-plaintext highlighter-rouge">type</code> in the edge file appears in the annotations file, and exactly one type
(<code class="language-plaintext highlighter-rouge">DNp01</code>) is <code class="language-plaintext highlighter-rouge">male-specific</code>. The five types are <code class="language-plaintext highlighter-rouge">DNp01</code>, <code class="language-plaintext highlighter-rouge">EPG</code>, <code class="language-plaintext highlighter-rouge">KCg-m</code>, <code class="language-plaintext highlighter-rouge">OA-VPM3</code>, <code class="language-plaintext highlighter-rouge">PEN_a</code>; the 12
rows become 9 pairs.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-connectome-as-a-prior/csr-matrix.svg" width="740" height="620" alt="The committed fixture's twelve segment rows summed into the nine nonzero (pre_type, post_type) pairs as a weighted five-by-five matrix; the sixteen empty cells are the absent pairs." />
  </picture>
  <figcaption>
    <p>The fixture's CSR as a weight matrix: the twelve segment rows summed into the nine nonzero
    <code>(pre_type, post_type)</code> pairs, the sixteen empty cells the absent pairs. Drawn by the
    committed <code>make_figures.py</code> from the fixture CSV, not pasted.</p>
  </figcaption>
</figure>

<p>Two error paths are pinned beside it. A missing file or a missing column is <code class="language-plaintext highlighter-rouge">PriorError::Read</code>. A row
whose body id is in no annotation is <strong>skipped and counted</strong>, not fatal: the test injects one such row
so the fixture holds 13 rows, and <code class="language-plaintext highlighter-rouge">build_type_graph_reporting</code> returns
<code class="language-plaintext highlighter-rouge">UnmappedRows { skipped: 1, total: 13 }</code> as a warning while the emitted CSR is unchanged. For a
dataset whose annotation table and edge table are separate downloads, the difference between “some
rows did not join” and “the build failed” is the difference between a usable warning and an outage.</p>

<h2 id="written-once-refused-on-reread">Written once, refused on reread</h2>

<p>The artifact is designed to be read by a crate that does not trust it. <code class="language-plaintext highlighter-rouge">manifest.json</code> carries four
digests — <code class="language-plaintext highlighter-rouge">source_sha256</code> over the whole <code class="language-plaintext highlighter-rouge">graph.bin</code>, and one per section — and the consumer
(<code class="language-plaintext highlighter-rouge">crates/jepa</code>) verifies them, and the size the counts imply, before decoding any array. The producer
also refuses to overwrite itself: if <code class="language-plaintext highlighter-rouge">dir</code> already holds a <code class="language-plaintext highlighter-rouge">manifest.json</code> whose <code class="language-plaintext highlighter-rouge">source_sha256</code>
matches, <code class="language-plaintext highlighter-rouge">write_prior</code> returns <code class="language-plaintext highlighter-rouge">AlreadyBuilt</code> <strong>before</strong> any write or <code class="language-plaintext highlighter-rouge">create_dir_all</code>. The test
compares name, mtime, length and bytes of all three files across the second call; the binary reports
the same thing on stderr and exits non-zero (<code class="language-plaintext highlighter-rouge">prior: prior already built from the same graph</code>, exit
1), while a first run prints one line to stdout: <code class="language-plaintext highlighter-rouge">prior: 5 types, 9 edges -&gt; &lt;dir&gt;</code>.</p>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Fixture segment edges</td>
      <td style="text-align: right">12</td>
      <td>rows</td>
      <td><code class="language-plaintext highlighter-rouge">crates/connectome-prior/tests/fixtures/mini-type-edges.csv</code></td>
    </tr>
    <tr>
      <td>Fixture types</td>
      <td style="text-align: right">5</td>
      <td>types</td>
      <td>same file</td>
    </tr>
    <tr>
      <td>Distinct type pairs after aggregation</td>
      <td style="text-align: right">9</td>
      <td>pairs</td>
      <td><code class="language-plaintext highlighter-rouge">ticket/T06</code> comment, T06/T09</td>
    </tr>
    <tr>
      <td>Builder tests</td>
      <td style="text-align: right">7</td>
      <td>tests</td>
      <td><code class="language-plaintext highlighter-rouge">cargo test -p qualia-connectome-prior</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">UnmappedRows</code> in the injected case</td>
      <td style="text-align: right">1 of 13</td>
      <td>rows</td>
      <td><code class="language-plaintext highlighter-rouge">skips_unmapped_rows_and_warns</code></td>
    </tr>
    <tr>
      <td>Arrow version used</td>
      <td style="text-align: right">56</td>
      <td>—</td>
      <td><code class="language-plaintext highlighter-rouge">crates/connectome-prior/Cargo.toml</code></td>
    </tr>
    <tr>
      <td>Packages dropped with arrow 53</td>
      <td style="text-align: right">14</td>
      <td>packages</td>
      <td><code class="language-plaintext highlighter-rouge">ticket/T06</code> comment</td>
    </tr>
    <tr>
      <td>Target-scale type edges (dataset)</td>
      <td style="text-align: right">929,735</td>
      <td>edges</td>
      <td>the earlier <a href="https://superposition.github.io/journal/the-male-cns-as-arrays/"><code class="language-plaintext highlighter-rouge">the-male-cns-as-arrays</code></a> entry ^1</td>
    </tr>
    <tr>
      <td>Target-scale types (dataset)</td>
      <td style="text-align: right">11,687</td>
      <td>types</td>
      <td>same ^1</td>
    </tr>
  </tbody>
</table>

<p>^1 The 929,735 / 11,687 pair is the dataset release figure quoted in the earlier journal entry
<a href="https://superposition.github.io/journal/the-male-cns-as-arrays/"><code class="language-plaintext highlighter-rouge">the-male-cns-as-arrays</code></a>, which was written in a different session from this one. It is the scale this
builder targets; it is <strong>not</strong> a measurement made by this ticket, whose only measured graph is the
9-pair fixture. The dataset numbers and the fixture numbers are different quantities and are not
comparable.</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/d6f19d7...2e288a4"><code class="language-plaintext highlighter-rouge">d6f19d7..2e288a4</code></a>: the workspace registration and fixture
commit, through the merge of the four builder commits. Epics:
<a href="https://github.com/superposition/qualia/issues/2">EPIC-02 (#2)</a> for the fixture and the members,
<a href="https://github.com/superposition/qualia/issues/3">EPIC-03 (#3)</a> for the crate.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>The dataset path is untested.</strong> Every measured number is from the 12-row fixture. The real build
reads two multi-gigabyte Feather exports; whether it completes, how much it skips and how long it
takes are unmeasured. The dataset’s own type graph is a release figure, not an output of this code.</li>
  <li><strong>No sign, no dimorphism, no dynamics.</strong> The edge table carries no excitatory/inhibitory column, and
the artifact is <code class="language-plaintext highlighter-rouge">rowptr</code>/<code class="language-plaintext highlighter-rouge">cols</code>/<code class="language-plaintext highlighter-rouge">weights</code> only. <code class="language-plaintext highlighter-rouge">dimorphism</code> is read from the annotations and then
aggregated away. The type names and the male-specific flag are in the input and not in the output.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">skipped</code> has never been non-trivial.</strong> The unmapped-row path was exercised with one injected row
out of 13. What the ratio is on the real download — where identity is per segment and the annotation
table has its own coverage gaps — is unknown.</li>
  <li><strong>The digests prove integrity, not provenance.</strong> <code class="language-plaintext highlighter-rouge">source_sha256</code> pinned in the manifest proves the
<code class="language-plaintext highlighter-rouge">graph.bin</code> next to it is the one that was written; it says nothing about which upstream export was
read. Attribution is a separate JSON file and is not signed.</li>
  <li><strong>The idempotence rule is exact-match only.</strong> A rebuilt artifact from updated inputs has a different
<code class="language-plaintext highlighter-rouge">source_sha256</code> and will overwrite the directory without asking. “Already built” means “built from
these exact bytes”, not “do not rebuild”.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="connectome" /><category term="csr" /><category term="offline-build" /><category term="provenance" /><summary type="html"><![CDATA[Turning a 929,735-edge type-level connectome into a checked, attributed artifact a belief layer can load — built offline, from two Feather files, with a 12-row fixture standing in for the dataset.]]></summary></entry><entry><title type="html">The licence and the snapshot</title><link href="https://superposition.github.io/journal/the-licence-and-the-snapshot/" rel="alternate" type="text/html" title="The licence and the snapshot" /><published>2026-09-11T16:30:00-04:00</published><updated>2026-09-11T16:30:00-04:00</updated><id>https://superposition.github.io/journal/the-licence-and-the-snapshot</id><content type="html" xml:base="https://superposition.github.io/journal/the-licence-and-the-snapshot/"><![CDATA[<p><strong>The claim.</strong> The public repository opens at commit <code class="language-plaintext highlighter-rouge">776bff0</code> with a five-file first commit —
<code class="language-plaintext highlighter-rouge">LICENSE</code>, <code class="language-plaintext highlighter-rouge">NOTICE</code>, <code class="language-plaintext highlighter-rouge">Cargo.toml</code>, <code class="language-plaintext highlighter-rouge">.gitignore</code> and one workflow — carrying <strong>Apache-2.0</strong> and no
prior history: <code class="language-plaintext highlighter-rouge">license = "Apache-2.0"</code> in the workspace package, <code class="language-plaintext highlighter-rouge">Copyright 2026 Superposition LLC</code>
in the licence text, and a NOTICE with exactly <strong>three</strong> attribution blocks (this product, the Leash
project under MIT, and the Male CNS dataset under CC-BY 4.0). What makes that more than a header is
the gate added at <code class="language-plaintext highlighter-rouge">144bb6d</code>: <code class="language-plaintext highlighter-rouge">scripts/provenance_check.py</code> compares every tracked file whose relative
path also exists in the private reference checkout, <strong>byte for byte</strong>, and reports the count. At
<code class="language-plaintext highlighter-rouge">144bb6d</code> it printed <strong>157 tracked files, 104 compared, 0 identical</strong>; at <code class="language-plaintext highlighter-rouge">a59b836</code>, the head when
the figures were drawn, <strong>170 tracked files, 110 compared, 0 identical</strong>. Both runs exited 0. Zero
copied files is a number you can check, and it is the whole claim.</p>

<h2 id="what-we-tried">What we tried</h2>

<p>The first shape was a snapshot with the history thrown away: <code class="language-plaintext highlighter-rouge">git archive HEAD | tar -x</code>, <code class="language-plaintext highlighter-rouge">git init</code>,
one commit. That is the shape that survived — the first commit is those five files, and every later
commit is written here.</p>

<p><strong>Relicensing was conditional, and the condition was checked.</strong> The ticket’s failure mode reads: if
any commit author in <code class="language-plaintext highlighter-rouge">git log --format='%ae' | sort -u</code> is not under the user’s control, keep those
files at MIT and note them in the NOTICE rather than relicense a third party’s work. The authors were
under control, so the workspace field became <code class="language-plaintext highlighter-rouge">license = "Apache-2.0"</code> and the per-crate manifests
point at it.</p>

<p><strong>The guard moved twice, and ended as a script.</strong> A <code class="language-plaintext highlighter-rouge">notice-check</code> workflow job tested
<code class="language-plaintext highlighter-rouge">test -s NOTICE &amp;&amp; grep -q "Leash project" NOTICE &amp;&amp; grep -q "CC-BY" NOTICE &amp;&amp; test -s LICENSE</code>.
When the workflows were dropped the same check became <code class="language-plaintext highlighter-rouge">.github/scripts/notice-check.sh</code>, so the guard
survives without CI. This is the first entry, so it is also where the pattern of handing a check to a
script instead of a runner starts.</p>

<p><strong>The provenance gate kept being wrong, in four distinguishable ways.</strong> The verifier’s first version
treated any byte-identical file as fatal, which flagged prose and rendered output that could not
plausibly have been copied: <code class="language-plaintext highlighter-rouge">provenance: a raw byte match is fatal unless the bytes are our own text</code>
(<code class="language-plaintext highlighter-rouge">7751c45</code>), then <code class="language-plaintext highlighter-rouge">judge the reference on what it records, not what it renders</code> (<code class="language-plaintext highlighter-rouge">b2b4a70</code>), then
<code class="language-plaintext highlighter-rouge">identity is fatal only for text this worktree authored</code> (<code class="language-plaintext highlighter-rouge">92e6871</code>). None of those were kept as
written. What was kept is <strong>text compared modulo line endings</strong> — <code class="language-plaintext highlighter-rouge">compare text modulo line endings
so the verdict ignores checkout settings</code> (<code class="language-plaintext highlighter-rouge">d99fe9a</code>) — because a Windows checkout writes CRLF and the
same file then reads as identical on one host and not on another. The final rule is in <code class="language-plaintext highlighter-rouge">b7ac824</code>
(<code class="language-plaintext highlighter-rouge">#160</code>): the identity verdict must not depend on checkout settings. The gate is also rooted at
<code class="language-plaintext highlighter-rouge">git rev-parse --show-toplevel</code> rather than at the script’s own directory (<code class="language-plaintext highlighter-rouge">902f286</code>), so running the
copy in a worktree measures that worktree and not <code class="language-plaintext highlighter-rouge">main</code>.</p>

<p><strong>Secrets were a rule, not a review.</strong> <code class="language-plaintext highlighter-rouge">.gitignore</code> carries <code class="language-plaintext highlighter-rouge">**/*.env</code>, <code class="language-plaintext highlighter-rouge">!**/*.env.example</code> and
<code class="language-plaintext highlighter-rouge">deploy/**/camera-stream.env</code>, so the one secret-shaped path in the private tree cannot be committed
by accident. <code class="language-plaintext highlighter-rouge">git check-ignore -v deploy/leash/camera-stream.env</code> prints the match.</p>

<h2 id="two-sources-one-file">Two sources, one file</h2>

<p>The NOTICE is where two other licences land, and neither of them is Apache-2.0:</p>

<ul>
  <li>software from the Leash project (<code class="language-plaintext highlighter-rouge">https://github.com/specdog/leash</code>) under <strong>MIT</strong>;</li>
  <li>the Male CNS connectome (<code class="language-plaintext highlighter-rouge">Berg et al. 2026</code>, <code class="language-plaintext highlighter-rouge">https://male-cns.janelia.org</code>) under <strong>CC-BY 4.0</strong>.</li>
</ul>

<p>So the repository’s licence is not one licence. Apache-2.0 covers the rewrite; MIT covers a dependency
whose work is <em>included</em>; CC-BY covers data <em>derived</em> from a published dataset. The NOTICE is the join.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-licence-and-the-snapshot/licence-flow.svg" width="1100" height="420" alt="A dashed boundary labelled clean room separates the private reference (read for interfaces only) from this repository. Below the line, three attribution sources — the relicensed workspace root, Leash under MIT, the Male CNS dataset under CC-BY 4.0 — fan into a NOTICE box, which is guarded by the notice-check script." />
  </picture>
  <figcaption>
    <p>The clean-room boundary and the three attributions that cross into the repository. The dashed
    line is the decision: interfaces may be read, bytes may not be copied. The NOTICE is the only
    place the other two licences appear, and the guard keeps all three strings present.</p>
  </figcaption>
</figure>

<h2 id="the-number-the-gate-prints">The number the gate prints</h2>

<p>The gate’s method is narrow on purpose: it compares only files whose <strong>relative path also exists</strong> in
the reference checkout, because everything else cannot have been copied. That is why the compared
count is smaller than the tracked count — 104 of 157, then 110 of 170.</p>

<figure class="measurement">
  <picture>
    <img src="https://raw.githubusercontent.com/superposition/qualia/main/docs/figures/the-licence-and-the-snapshot/provenance-check.svg" width="1100" height="460" alt="For each of two commits, three bars: files tracked in this repository, files whose relative path also exists in the private reference checkout, and files byte-identical to it. At 144bb6d: 157, 104, 0. At a59b836: 170, 110, 0." />
  </picture>
  <figcaption>
    <p>Tracked, compared, identical — at the commit that introduced the check and at the head when it
    was last run. The third bar is zero at both. Drawn by the committed
    <code>make_figures.py</code> from <code>provenance.json</code>, not pasted.</p>
  </figcaption>
</figure>

<h2 id="evidence">Evidence</h2>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Unit</th>
      <th>Source</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>First commit’s files</td>
      <td style="text-align: right">5</td>
      <td>files</td>
      <td><code class="language-plaintext highlighter-rouge">git show --stat 776bff0</code></td>
    </tr>
    <tr>
      <td>Attribution blocks in <code class="language-plaintext highlighter-rouge">NOTICE</code></td>
      <td style="text-align: right">3</td>
      <td>blocks</td>
      <td><code class="language-plaintext highlighter-rouge">NOTICE</code> ^1</td>
    </tr>
    <tr>
      <td>Workspace licence</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">Apache-2.0</code></td>
      <td>—</td>
      <td><code class="language-plaintext highlighter-rouge">Cargo.toml</code> <code class="language-plaintext highlighter-rouge">[workspace.package]</code> ^1</td>
    </tr>
    <tr>
      <td>Tracked files at <code class="language-plaintext highlighter-rouge">144bb6d</code></td>
      <td style="text-align: right">157</td>
      <td>files</td>
      <td><code class="language-plaintext highlighter-rouge">provenance.json</code> ^2</td>
    </tr>
    <tr>
      <td>Files compared at <code class="language-plaintext highlighter-rouge">144bb6d</code></td>
      <td style="text-align: right">104</td>
      <td>files</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Byte-identical at <code class="language-plaintext highlighter-rouge">144bb6d</code></td>
      <td style="text-align: right">0</td>
      <td>files</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Tracked files at <code class="language-plaintext highlighter-rouge">a59b836</code></td>
      <td style="text-align: right">170</td>
      <td>files</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Files compared at <code class="language-plaintext highlighter-rouge">a59b836</code></td>
      <td style="text-align: right">110</td>
      <td>files</td>
      <td>same ^2</td>
    </tr>
    <tr>
      <td>Byte-identical at <code class="language-plaintext highlighter-rouge">a59b836</code></td>
      <td style="text-align: right">0</td>
      <td>files</td>
      <td>same ^2</td>
    </tr>
  </tbody>
</table>

<p>^1 Read from the committed file at <code class="language-plaintext highlighter-rouge">main</code>, not from this text.
^2 <code class="language-plaintext highlighter-rouge">docs/figures/the-licence-and-the-snapshot/provenance.json</code>. The two runs were taken in
a later session than the commits they measure; the commits are <code class="language-plaintext highlighter-rouge">144bb6d</code> (which introduced the check)
and <code class="language-plaintext highlighter-rouge">a59b836</code> (the head then).</p>

<p>The commit range this entry describes is <a href="https://github.com/superposition/qualia/compare/776bff0...144bb6d"><code class="language-plaintext highlighter-rouge">776bff0..144bb6d</code></a> — the snapshot and licence files through
the commit that added the provenance gate. <code class="language-plaintext highlighter-rouge">776bff0</code> is the first commit on <code class="language-plaintext highlighter-rouge">main</code>; there is no
history before it. A later run recorded in <code class="language-plaintext highlighter-rouge">provenance.json</code> is taken at <code class="language-plaintext highlighter-rouge">a59b836</code>.
The rewrite itself is <a href="https://github.com/superposition/qualia/issues/66">EPIC-00 (#66)</a>; this entry’s
epic is <a href="https://github.com/superposition/qualia/issues/1">EPIC-01 (#1)</a>.</p>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<ul>
  <li><strong>Zero identical is measured against one checkout.</strong> The gate compares against the private
reference tree present on the machine it runs on. A different revision of the reference, or none at
all, gives a different number; the verdict is only as good as that checkout. The reference’s path is
deliberately not recorded in the committed data.</li>
  <li><strong>The comparison is byte equality, not similarity.</strong> A file that is 90 % copied is not identical and
the gate passes it. Reformatting defeats the check; the check is a floor, not a proof of
authorship.</li>
  <li><strong>Two runs are recorded, not a continuous measurement.</strong> <code class="language-plaintext highlighter-rouge">144bb6d</code> and <code class="language-plaintext highlighter-rouge">a59b836</code> are the two runs in
<code class="language-plaintext highlighter-rouge">provenance.json</code>. Nothing re-runs the gate on every commit.</li>
  <li><strong>Not a legal opinion.</strong> That the NOTICE’s MIT and CC-BY attributions are the ones that are owed
was decided by the plan’s step text, not by counsel; no third party audited the result.</li>
  <li><strong>The 104/157 split is a path coincidence, not an audit.</strong> A file is compared only when a
same-relative-path file exists in the reference; files that differ in name are never compared, so
“0 identical” does not mean “0 files read”.</li>
</ul>]]></content><author><name>Superposition</name></author><category term="clean-room" /><category term="licence" /><category term="provenance" /><category term="engineering" /><summary type="html"><![CDATA[In a clean-room rewrite the licence and the proof of non-copying are the deliverable, not paperwork around it. Apache-2.0, a NOTICE carrying three attributions, and a gate that compared 104 then 110 files against the private reference and found 0 identical.]]></summary></entry><entry><title type="html">The male CNS, as arrays</title><link href="https://superposition.github.io/journal/the-male-cns-as-arrays/" rel="alternate" type="text/html" title="The male CNS, as arrays" /><published>2026-09-10T21:30:00-04:00</published><updated>2026-09-10T21:30:00-04:00</updated><id>https://superposition.github.io/journal/the-male-cns-as-arrays</id><content type="html" xml:base="https://superposition.github.io/journal/the-male-cns-as-arrays/"><![CDATA[<figure class="mesh-band" data-colors="#91dbba,#c9b2ff,#93caff,#e0a08a" data-weights="1,0.55,0.63,0.47">
  <canvas aria-hidden="true" focusable="false"></canvas>
  <figcaption>
    <p>The four spots are the four cross-sex classes of cell type, opacity set by the log of each class's count: isomorphic, dimorphic, male-specific, female-specific.</p>
    <span class="mesh-band-credit">Field: <a href="https://github.com/paper-design/shaders" rel="noopener">Paper Shaders</a> mesh gradient (Apache-2.0), palette and weights from this post.</span>
  </figcaption>
</figure>
<p><strong>The claim.</strong> The whole central nervous system of a male fruit fly is now public data — <strong>166,700
neurons</strong>, <strong>11,710 cell types</strong>, 45.6 million pre-synaptic sites — and it is small enough to hold on
one workstation. Reduce it to the graph <em>between cell types</em> and it becomes 929,735 edges over 11,687
types, which is a graph a GPU can sweep thousands of times while you wait. What is computable is
therefore no longer “where does this neuron go” but “what happens to the circuit if this class of
neuron is rewired” — and the classes that differ between the sexes are an enumerable list: 138
dimorphic and 289 male-specific types. That list is the thing worth computing on, and it is the thing
that can be handed to a robot as a cost.</p>

<p>This post is a map and a plan, not a result. Every number below is the dataset’s; nothing on it has
been computed yet, and the last section says exactly where the plan stops.</p>

<h2 id="what-the-map-is">What the map is</h2>

<p>One adult male, all of it: central brain, both optic lobes, and the ventral nerve cord in a single
seamless volume — the first complete male CNS connectome, published in <em>Cell</em> in 2026 with a preprint
in 2025.</p>

<table>
  <thead>
    <tr>
      <th>Quantity</th>
      <th style="text-align: right">Value</th>
      <th>Where it comes from</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Neurons</td>
      <td style="text-align: right">166,700</td>
      <td>Berg et al. 2026, <em>Cell</em></td>
    </tr>
    <tr>
      <td>Cell types</td>
      <td style="text-align: right">11,710</td>
      <td>same</td>
    </tr>
    <tr>
      <td>Pre-synaptic sites (T-bars)</td>
      <td style="text-align: right">45,656,140</td>
      <td><code class="language-plaintext highlighter-rouge">Neuprint_Meta.csv</code>, <code class="language-plaintext highlighter-rouge">male-cns:v1.0</code></td>
    </tr>
    <tr>
      <td>Post-synaptic sites</td>
      <td style="text-align: right">311,833,243</td>
      <td>same</td>
    </tr>
    <tr>
      <td>Segment-to-segment edges</td>
      <td style="text-align: right">151,856,684</td>
      <td><code class="language-plaintext highlighter-rouge">connectome-weights</code> export</td>
    </tr>
    <tr>
      <td>Neuron-to-neuron edges with valid superclasses</td>
      <td style="text-align: right">25,563,426</td>
      <td>the paper’s own notebook</td>
    </tr>
    <tr>
      <td>Edges at weight ≥ 5</td>
      <td style="text-align: right">6,237,402</td>
      <td>same</td>
    </tr>
    <tr>
      <td><strong>Type-to-type edges</strong></td>
      <td style="text-align: right"><strong>929,735</strong></td>
      <td>same, aggregated over 11,687 types</td>
    </tr>
  </tbody>
</table>

<p><em>All eight values are quoted; the last line is the one that matters here.</em></p>

<p>The type-level graph is the useful scale. Written as a dense matrix it would be</p>

\[\frac{929{,}735}{11{,}687^{2}} \;\approx\; 6.8 \times 10^{-6}\]

<p>that is, about seven entries in a million — sparse enough to store as a list, small enough to hold
several copies of, which is what makes sweeps affordable.</p>

<p>The sex comparison is where the numbers get sharp. Against the female FlyWire connectome, the types
split into <strong>8,069 isomorphic, 138 dimorphic, 289 male-specific and 71 female-specific</strong>. Put
differently: roughly 95% of cells are shared, about 12% of neurons in the male brain show wiring
differences against fewer than 3% in the female brain, and the male-specific and dimorphic types
together are a few hundred names — small enough to enumerate by hand, large enough to be a real
circuit.</p>

<h2 id="how-it-gets-onto-one-machine">How it gets onto one machine</h2>

<p>Two doors, and they are not equivalent:</p>

<p><strong>Python, for arrays.</strong> <code class="language-plaintext highlighter-rouge">neuprint-python</code> talks to the server at <code class="language-plaintext highlighter-rouge">neuprint.janelia.org</code> and returns
pandas or Arrow tables; <code class="language-plaintext highlighter-rouge">navis</code> and <code class="language-plaintext highlighter-rouge">navis-flybrains</code> handle skeletons, meshes and coordinate
transforms. This is the door for anyone who wants the connectivity as arrays and a GPU underneath it.</p>

<p><strong>R, for the annotation ecosystem.</strong> <code class="language-plaintext highlighter-rouge">neuprintr</code> plus <code class="language-plaintext highlighter-rouge">malevnc</code> (the nerve-cord subset, MANC: about
23,000 neurons, 10 million pre-synaptic sites, 74 million post-synaptic densities) or <code class="language-plaintext highlighter-rouge">malecns</code> (the
whole CNS). <code class="language-plaintext highlighter-rouge">malecns</code> is, in its own words, “a very thin wrapper around the malevnc package”. This is
the door for Clio annotations and template-brain registration across light-level templates.</p>

<p>The bulk data sits on a public Google Cloud bucket, and this is the part that decides what kind of
work is possible:</p>

<table>
  <thead>
    <tr>
      <th>Export</th>
      <th style="text-align: right">Size</th>
      <th style="text-align: right">Rows</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">syn-points</code> (pre + post)</td>
      <td style="text-align: right">13.061 GB</td>
      <td style="text-align: right">357,489,383</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">syn-partners</code> (one row per post-synaptic contact)</td>
      <td style="text-align: right">6.777 GB</td>
      <td style="text-align: right">311,833,243</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">connectome-weights</code> (segment to segment)</td>
      <td style="text-align: right">1.051 GB</td>
      <td style="text-align: right">151,856,684</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Neuprint_Neurons</code> (all segments)</td>
      <td style="text-align: right">4.649 GB</td>
      <td style="text-align: right">88,682,452</td>
    </tr>
  </tbody>
</table>

<p><em>Row counts are read from each file’s Arrow footer, and the first two check out against the dataset’s
own metadata: $45{,}656{,}140 + 311{,}833{,}243 = 357{,}489{,}383$.</em></p>

<p>That is a couple of hundred gigabytes of local disk at most, and the connectivity itself — the
1.051 GB export — is a file you can open in a notebook.</p>

<p>Four things make the wrangling harder than the download, and all four are worth knowing before
writing code:</p>

<ul>
  <li><strong>Identity is per segment, not per neuron.</strong> The <code class="language-plaintext highlighter-rouge">Neuprint_Neurons</code> export has 88.7 million rows,
because it also carries untraced fragments. The neuron count comes from the annotation table
(211,577 rows with curated annotation) and from the <code class="language-plaintext highlighter-rouge">status</code> field, not from the row count.</li>
  <li><strong>A pre-synaptic site is not a connection.</strong> One T-bar can contact several partners, so
connections exceed pre-synaptic sites; <code class="language-plaintext highlighter-rouge">weight</code> on the <code class="language-plaintext highlighter-rouge">ConnectsTo</code> edge is the count of contacts.
Connections and synapses are different quantities and the press numbers mix them.</li>
  <li><strong>Sign is inferred.</strong> There is no excitatory/inhibitory column. There are predicted
neurotransmitter probabilities per neuron and per T-bar — ACh, GABA, glutamate, dopamine,
octopamine, serotonin, histamine, tyramine — and the sign is a reading of those.</li>
  <li><strong>The join keys are the point.</strong> Each type can carry <code class="language-plaintext highlighter-rouge">flywireType</code>, <code class="language-plaintext highlighter-rouge">mancType</code>, <code class="language-plaintext highlighter-rouge">hemibrainType</code>,
<code class="language-plaintext highlighter-rouge">vfbId</code> and a <code class="language-plaintext highlighter-rouge">itoleeHl</code> hemilineage; 8,137 of the 11,751 type entries in the explorer carry a
FlyWire type. Cross-dataset work is a join on those columns, and where they are empty the join is
simply unavailable.</li>
</ul>

<h2 id="what-the-gpu-is-actually-for">What the GPU is actually for</h2>

<p>Not size. The adjacency is 1 GB, and any laptop holds that. The GPU is for <strong>repetition</strong>: every
question worth asking about a circuit is a null test — how surprising is this many connections
between these two types; what survives if these 289 types are rewired at random; which dimorphic
types are dimorphic in a <em>structured</em> way rather than by drift. Each of those is a full pass over the
edge list, and there are thousands of them.</p>

<p>The primitive is one we have already measured. Neighbour aggregation over a CSR edge list — a
<code class="language-plaintext highlighter-rouge">rowptr</code> array, an <code class="language-plaintext highlighter-rouge">indices</code> array, a <code class="language-plaintext highlighter-rouge">weights</code> array, one output row per input row — is exactly the
shape of a connectome statistic, and on the RTX 4090 it runs at <strong>7.06 µs over 65,536 edges</strong> after
the load-widening change (Triton’s kernel, 5.97 µs, is still ahead). The type graph is about fourteen
times larger, so one statistical sweep is on the order of a tenth of a millisecond; ten thousand
permutations then cost seconds, not hours, and that is the whole argument for the card.</p>

<figure class="measurement">
  <picture>
    <img src="/mage/assets/figures/fly-cns/fly-cns-csr.svg" width="1100" height="560" alt="Two schematics. Above: the neuron table, sorted into four blocks by cross-sex class — 8,069 isomorphic types, 138 dimorphic, 289 male-specific, 71 female-specific — so that every per-type statistic is a segmented reduction. Below: the CSR edge list, rowptr plus indices plus weights, with 166,701 offsets, 25,563,426 neuron-level edges, 6,237,402 edges at weight five or more, and 929,735 type-to-type edges." />
  </picture>
  <figcaption>
    <p>The connectome as the two arrays a kernel actually reads. Sorting by type is what makes the per-type statistics a segmented reduce instead of a sort inside the kernel. <a href="/mage/assets/figures/fly-cns/fly-cns-csr.svg" download="">Download the SVG</a>.</p>
  </figcaption>
</figure>

<p>Three kernels cover most of it: a <strong>degree and sign census</strong> (one pass, per-type segmented reduce), a
<strong>two-hop reach</strong> — sparse × sparse, $929{,}735 \times 929{,}735$ at type level, which is how you ask
“what does this class touch through one intermediate” — and <strong>permutation tests</strong>, the same census run
across shuffled adjacency, where the GPU’s job is to run many tiny independent versions of the same
kernel rather than one large one.</p>

<h2 id="how-it-drives">How it drives</h2>

<p>The loop it feeds already exists, in two repositories.</p>

<p><strong><code class="language-plaintext highlighter-rouge">leash</code></strong> is a safety-gated Rust robotics runtime: CLI, HTTP and MCP control over simulation,
replay and physical hardware, with the safety authority — authorization, approval, deadman, freshness,
collision, distance, stop, latching E-stop — held by the runtime and not by the caller. Its compute
surface is exactly what this needs: a bounded, authenticated, <strong>advisory</strong> job API
(<code class="language-plaintext highlighter-rouge">POST /compute/jobs</code>, results capped at 1 MiB, at most two concurrent, deadlines up to 120 seconds)
whose own documentation states that compute results “cannot authorize or refresh motor output”. The
<code class="language-plaintext highlighter-rouge">leash-cuda</code> crate owns the on-robot CUDA contract: a checked-in fatbin for the Jetson Orin NX
(SM 8.7, CUDA 12.9, SHA-256 recorded in a manifest, six kernels each compared against a CPU oracle),
built deliberately rather than compiled at startup.</p>

<p><strong><code class="language-plaintext highlighter-rouge">qualia</code></strong> is the runtime that carries the higher-order state, and its planner speaks a frozen
contract: <code class="language-plaintext highlighter-rouge">plan_path</code> over a local socket as newline-delimited JSON, taking a start pose, a goal pose,
an occupancy grid, constraints — and a <code class="language-plaintext highlighter-rouge">belief_risk</code> block of two floats:</p>

\[\text{path\_cost} \;\mathrel{+}=\; \big(\text{uncertainty\_weight} \times 12 \;+\; \text{novelty} \times 4\big) \times \text{resolution}_m\]

<p>That is the seam. The planner today is grid-only — A* or uniform cost over a 2D occupancy grid — so a
connectome does not become the planner. It becomes a <strong>prior on the cost</strong>: a table saying where the
male-specific and dimorphic circuitry is involved, which the planner already knows how to price in,
with the evidence attached and the authority left where it is.</p>

<figure class="measurement">
  <picture>
    <img src="/mage/assets/figures/fly-cns/fly-cns-loop.svg" width="1100" height="400" alt="A pipeline of five blocks: the male-cns:v1.0 dataset, a workstation GPU computing CSR statistics and null tests, a compressed type-level prior and risk table, the leash-cuda fatbin on a Jetson Orin NX, and the qualia planner taking plan_path with a belief_risk cost. A dashed line marks that everything downstream of the dataset is advisory: leash keeps the collision, deadman, stop and E-stop gates." />
  </picture>
  <figcaption>
    <p>The path from a connectome to a robot's cost function. The dashed rule is the important line in the diagram: the numbers are advisory, and the gates that can stop a motor stay with <code>leash</code>. <a href="/mage/assets/figures/fly-cns/fly-cns-loop.svg" download="">Download the SVG</a>.</p>
  </figcaption>
</figure>

<h2 id="what-this-does-not-establish">What this does not establish</h2>

<p><strong>Nothing on this page has been computed.</strong> The dataset numbers are quoted from the paper, the
release metadata and the exports; the graph sizes are read from file footers; the kernel time is from
the earlier profiling session and is a neighbour-aggregation kernel on synthetic edges, not on this
data. The plan — map, compute, price — is a plan.</p>

<p>Beyond that, four things are open or unresolved and none of them are small:</p>

<ul>
  <li><strong>The step from structure to a cost is the research problem.</strong> Knowing that 289 types are
male-specific does not say what a robot should do differently. Nothing here identifies which of
those types, if any, corresponds to a navigational decision; that mapping would have to be earned.</li>
  <li><strong>Version and count discrepancies.</strong> The paper says 11,710 types, the v1.0 explorer says 11,751, and
the preprint said 11,691; the explorer’s catalog sums to 164,838 cells against the paper’s 166,700
neurons. Two different dataset UUIDs circulate (one in the neuprint metadata, one in the explorer).
I have not resolved any of these.</li>
  <li><strong>The press figure is not the table figure.</strong> “125 million synaptic connections” does not match the
311.8 M post-synaptic sites or the 151.9 M segment-to-segment edges; the arithmetic that reconciles
them is not stated in any source I found, and I have not asserted one.</li>
  <li><strong>Sign, and the parts of the nervous system the plan ignores.</strong> Excitatory/inhibitory is inferred
from neurotransmitter prediction, not measured. Neuromodulation, gap junctions, and everything
that is not a chemical synapse are outside the edge list; so is the animal, since a connectome
recorded from one male fly is a single sample of a species.</li>
</ul>

<p>The <a href="https://male-cns.janelia.org/download/">download page</a> has the exports; the
<a href="https://www.cell.com/cell/fulltext/S0092-8674(26)00942-6">paper</a> and its
<a href="https://www.biorxiv.org/content/10.1101/2025.10.09.680999v2">preprint</a> have the biology;
<a href="https://github.com/natverse/malecns"><code class="language-plaintext highlighter-rouge">malecns</code></a> and
<a href="https://github.com/flyconnectome/2025malecns"><code class="language-plaintext highlighter-rouge">2025malecns</code></a> are the two access paths this post uses;
<a href="https://github.com/specdog/leash"><code class="language-plaintext highlighter-rouge">leash</code></a> is where the numbers would land.</p>]]></content><author><name>Superposition</name></author><category term="connectome" /><category term="cuda" /><category term="robotics" /><category term="mapping" /><summary type="html"><![CDATA[The complete male fruit fly central nervous system — 166,700 neurons, 11,710 types, 45.6 million pre-synaptic sites — is public, fits on one workstation, and reduces to a 929,735-edge graph between types. That is small enough to compute on a GPU and specific enough to steer a robot with.]]></summary></entry><entry><title type="html">Tiles the compiler chose</title><link href="https://superposition.github.io/journal/tiles-the-compiler-chose/" rel="alternate" type="text/html" title="Tiles the compiler chose" /><published>2026-09-10T20:55:00-04:00</published><updated>2026-09-10T20:55:00-04:00</updated><id>https://superposition.github.io/journal/tiles-the-compiler-chose</id><content type="html" xml:base="https://superposition.github.io/journal/tiles-the-compiler-chose/"><![CDATA[<figure class="mesh-band" data-colors="#93caff,#91dbba,#c9b2ff,#e0a08a" data-weights="0.74,1,0.62,0.90">
  <canvas aria-hidden="true" focusable="false"></canvas>
  <noscript><img src="https://superposition.github.io/mage/assets/figures/mage-004/mesh-band.png" alt="A dark field with four soft spots of colour — blue, green, lavender and warm sand — scaled by how competitive each implementation is." width="923" height="213" /></noscript>
  <figcaption>
    <p>The four spots are the four implementations, opacity set by how competitive each is.</p>
    <span class="mesh-band-credit">Field: <a href="https://github.com/paper-design/shaders" rel="noopener">Paper Shaders</a> mesh gradient (Apache-2.0), palette and weights from this post.</span>
  </figcaption>
</figure>
<p><strong>The claim.</strong> Give a compiler the job of deciding how a GPU kernel places its data, and it will do
well where reuse is low and worse where reuse is high. On five FP32 operations, the cuTile Rust tile
kernels beat the hand-written kernels on bias + GELU — $8.19\ \mu s$ against $11.0$ — drew on layer
normalization, and lost on matrix multiply, triangle contraction and neighbor aggregation by
$1.6\times$, $1.4\times$ and $3.4\times$.</p>

<p>Two arguments carry that claim, and both are about memory rather than arithmetic.</p>

<h2 id="reuse-is-a-layout-problem">Reuse is a layout problem</h2>

<p>A thread that computes one output element of $C = A B$ reads one value of $A$ and one of $B$ per
multiply-add. A thread that computes a $4\times4$ block reads four of each and performs sixteen
multiply-adds, so shared-memory reads per multiply-add fall from $\tfrac{2}{1}$ to
$\tfrac{8}{16} = 0.5$ — and loading those as 128-bit quads takes it to $0.125$: one instruction
fetching all four values the thread needs.</p>

<figure class="measurement">
  <picture>
    <source media="(max-width: 520px)" srcset="/mage/assets/figures/mage-004/matmul-layouts-mobile.svg" />
    <img src="/mage/assets/figures/mage-004/matmul-layouts.svg" width="740" height="278" alt="Two schematics side by side. Left, the cuTile Rust tile layout: a grid of 32 by 128 tiles, one program per tile, loading 32 by 32 operands per contraction step as 128-bit loads. Right, the cuda-oxide layout: a 64 by 64 block with a 4 by 4 register tile per thread, and shared memory holding A transposed with row stride 68 so each thread's four rows are contiguous." />
  </picture>
  <figcaption>
    <p>The same product, two ways of placing it in memory: the compiler decides how the tile is threaded and how wide the loads are, the kernel author decides the register tile and the transposed $A$. <a href="/mage/assets/figures/mage-004/matmul-layouts.svg" download="">Download the SVG</a>.</p>
  </figcaption>
</figure>

<p>The tile compiler is not blind to any of this: it widens loads too, and it partitions the output into
$32\times128$ tiles with $32\times32$ operands per contraction step. What it cannot know is that this
problem wants a particular arrangement. Its matrix multiply is $1.6\times$ slower, and no arithmetic
explains that — only where the operands sit when the multiply issues.</p>

<h2 id="the-clock-measures-two-things">The clock measures two things</h2>

<p>Time around a call is submission plus execution:</p>

\[\text{span} \;=\; \underbrace{t_{\text{submit}}}_{\text{host builds and queues}} \;+\; \underbrace{t_{\text{kernel}}}_{\text{device runs}} \;+\; \text{idle}\]

<p>The tile runtime submits lazily, and one awaited call costs $14\text{–}23\ \mu s$ of host time
against $2\text{–}3\ \mu s$ for the hand-written kernel. It is the difference between a taxi meter
that starts when you pick up the phone and one that starts when the wheels turn: a comparison that
waits for every call is comparing phone calls, not journeys. Bias + GELU measures
$29.97\ \mu s$ around a kernel that runs in $8.19\ \mu s$. Queue the calls, or replay them from a
recorded CUDA graph, and every operation lands on its kernel time:</p>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th style="text-align: right">awaited</th>
      <th style="text-align: right">queued in tens</th>
      <th style="text-align: right">kernel only</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Matrix multiplication $1024^3$</td>
      <td style="text-align: right">150.53</td>
      <td style="text-align: right">127.07</td>
      <td style="text-align: right">131.56</td>
    </tr>
    <tr>
      <td>Bias + GELU $4096\times768$</td>
      <td style="text-align: right">25.76</td>
      <td style="text-align: right">8.50</td>
      <td style="text-align: right">8.19</td>
    </tr>
    <tr>
      <td>LayerNorm $4096\times768$</td>
      <td style="text-align: right">30.62</td>
      <td style="text-align: right">10.64</td>
      <td style="text-align: right">10.76</td>
    </tr>
    <tr>
      <td>Triangle contraction $128\times32$</td>
      <td style="text-align: right">136.19</td>
      <td style="text-align: right">121.80</td>
      <td style="text-align: right">116.08</td>
    </tr>
    <tr>
      <td>Neighbor aggregation $4096\times64\times65536$</td>
      <td style="text-align: right">49.28</td>
      <td style="text-align: right">33.28</td>
      <td style="text-align: right">35.37</td>
    </tr>
  </tbody>
</table>

<p><em>Microseconds, mean of 100 launches. Replay reaches $7.77\ \mu s$ on bias + GELU. Timed the same way,
Triton and PyTorch also improve, by $6\text{–}7\ \mu s$ and about $1\ \mu s$ per call.</em></p>

<h2 id="evidence">Evidence</h2>

<p>Kernel time from separate Nsight Systems captures, 100 launches each. Every output was checked
against PyTorch with TF32 disabled before any timing was believed.</p>

<table>
  <thead>
    <tr>
      <th>Operation</th>
      <th style="text-align: right">PyTorch</th>
      <th style="text-align: right">Triton</th>
      <th style="text-align: right">cuTile Rust</th>
      <th style="text-align: right">cuda-oxide Rust</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Matrix multiplication $1024^3$</td>
      <td style="text-align: right">56.04</td>
      <td style="text-align: right">83.06</td>
      <td style="text-align: right">131.56</td>
      <td style="text-align: right"><strong>80.00</strong></td>
    </tr>
    <tr>
      <td>Bias + GELU $4096\times768$</td>
      <td style="text-align: right">15.88</td>
      <td style="text-align: right">7.73</td>
      <td style="text-align: right"><strong>8.19</strong></td>
      <td style="text-align: right">11.0</td>
    </tr>
    <tr>
      <td>LayerNorm $4096\times768$</td>
      <td style="text-align: right">11.42</td>
      <td style="text-align: right">8.15</td>
      <td style="text-align: right">10.76</td>
      <td style="text-align: right">10.05</td>
    </tr>
    <tr>
      <td>Triangle contraction $128\times32$</td>
      <td style="text-align: right">28.64</td>
      <td style="text-align: right">102.19</td>
      <td style="text-align: right">116.08</td>
      <td style="text-align: right">80.1</td>
    </tr>
    <tr>
      <td>Neighbor aggregation $4096\times64\times65536$</td>
      <td style="text-align: right">67.32</td>
      <td style="text-align: right">7.97</td>
      <td style="text-align: right">35.37</td>
      <td style="text-align: right">10.3</td>
    </tr>
  </tbody>
</table>

<p><em>Microseconds of GPU kernel time per operation. Layer normalization is worth reading twice: the tile
kernel pads every $768$-wide row out to $1024$, because tile dimensions must be powers of two, so a
third of its lanes do nothing — and it still draws.</em></p>

<p>Tile shape turned out to be the same kind of decision: the identical kernel measured $738\ \mu s$ at
the tutorial’s $16\times16\times8$ tile and $131.56\ \mu s$ at $32\times128\times32$, and
$128\times128\times8$ was $2.3\times$ slower than a <em>smaller</em> tile. That non-monotonicity is a
register or occupancy cliff, not arithmetic.</p>

<h2 id="what-was-tried-and-not-kept">What was tried and not kept</h2>

<ul>
  <li><strong>A broadcast product instead of the matrix instruction.</strong> It did not compile, and the matrix
instruction kept FP32 accuracy anyway: $1.5\times10^{-5}$ against the strict reference at
$K = 1024$ — accumulation error, not a 10-bit mantissa’s.</li>
  <li><strong>Deeper contraction steps at small tiles.</strong> $16\times16\times32$ measured $1072\ \mu s$ against
$738$ at $16\times16\times8$.</li>
  <li><strong>A loop over the channel axis in the triangle kernel.</strong> Every channel read the first channel’s
values; a partition load indexed by a loop variable does not vary, so the channel has to come from
the grid axes.</li>
  <li><strong>One row per program for layer norm.</strong> It runs, but it forces the $768 \to 1024$ padding.</li>
</ul>

<h2 id="what-these-numbers-do-not-establish">What these numbers do not establish</h2>

<p>No hardware counters are available on this host, so occupancy and bandwidth are inferred from ratios
rather than read. The cuda-oxide column is a previous round’s measurement, not taken in the same
session, so the two Rust columns should not be subtracted from each other. One capture per operation
means a kernel time carries no interval of its own, and compilation, transfers and process startup
are excluded throughout.</p>

<p>The <a href="https://superposition.github.io/mage/experiments/mage-004/">field note</a> has the full tables, and
the <a href="https://github.com/superposition/mage/blob/master/docs/experiments/mage-004.md">technical record</a>
has the method, the compiler’s constraints and the reproduction commands.</p>]]></content><author><name>Superposition</name></author><category term="kernels" /><category term="measurement" /><category term="performance" /><category term="cutile" /><summary type="html"><![CDATA[A tile compiler met the hand-written kernels on five FP32 operations. It won one, matched another and lost two — and the losses are exactly where data reuse is highest, which is where layout decides the answer.]]></summary></entry></feed>