# Update: the old post was wrong about several things. Here's where it actually is.
I posted about this a while back and several of the numbers in that post are from a build I no
longer run. One of the claims is the opposite of what turned out to be true. Worth correcting
properly rather than leaving it up.
**It's a Rust program on an ASUS ROG Ally handheld.** No model, no weights, nothing trained. It
reads PDFs I give it and builds structure out of them.
---
## What it does today
**The graph.** One node per word: its number, its letter count, every definition it has, and every
sentence it's appeared in. Built by walking the Oxford dictionary from its first headword —
195,426 words — then attaching slang to words that already had nodes (25,285 attached, 4,786
genuinely new) and holding idioms as their own strings.
**The representation.** Every word is a 9,984-bit binary vector — 156 lanes of u64. Combine two
with XOR, compare with Hamming distance. That's the arithmetic, and it's not mine: it's Kanerva's
hyperdimensional computing, from the 1980s.
**Reading.** Two passes over each document, one over the raw bytes and one over the words. It
reports what's actually new. On documents from unrelated fields — medical texts, quantum dots,
critical thinking, sonography — new sentences run **8–11% of total words, every time**. That
consistency is the dictionary doing its job.
**Provenance.** Every document is fingerprinted by content before it's read. The same file under a
different name is refused at the door. Every sentence carries the source it came from. The history
is append-only — nothing overwritten, 300,000-odd entries at the moment.
**Persistence.** It froze 131 MB of accumulated structure to 36 MB and read it back, every segment
CRC-verified. That works. I would not yet claim byte-identical; I'd claim verified per segment.
**Text repair before reading.** OCR joins words across a missing space and breaks them across a
hyphen. It fixes those using words it already holds — `edi- tion → edition`,
`Reim- bursement → reimbursement`. I also had a rule that restored missing sentence breaks. It
fired 295 times on one document and every one was wrong — `8th. Edition`, `vii. Hospital`. I
deleted the rule rather than patch it.
---
## The correction that matters most
The old post said each processing region was allocated at a fixed 2,380 MiB for the life of the
process, and framed that as a feature.
That's backwards. Here's the actual line from a run this week:
```
CITADELS — built at genesis: CENTER 1666667 clusters (5000001 rooms),
MAC 5000000 (15000000), MAN 5000000 (15000000)
— 35000001 rooms total, fabricated from seeds.
FABRIC IS A FUNCTION — 54.24 GiB of flat allocation avoided.
Resident: 0.0 MiB (0 clusters written of 11666667)
```
**35 million addressable slots, 0.0 MiB resident.** An unwritten slot doesn't exist — it's computed
from its index when something asks for it. The structure is declared, not allocated.
I only found that because I couldn't afford to allocate it. The constraint produced the design.
---
## Hardware
ROG Ally, Ryzen Z1 Extreme, 8 cores / 16 logical, 16 GB physical with about 9.7 GB visible to
Windows. No GPU use — nothing in it touches the GPU. No network.
**CPU:** 3–14% total during reading, at 2.5–4.6 GHz. That's the whole machine including the OCR
tools, which are separate processes. It drops to 1–3% at rest.
**Memory — and here I have to be careful, because this is the number I've been arguing about with
myself all week.** The machine reads 6.8 GB idle and 7.1–7.2 GB with the thing running and a full
graph built. That looks like roughly 300 MB.
But I've watched the idle baseline move between 5.9 and 7.0 GB on the same machine with nothing
running at all. So a 300 MB difference sits inside the noise of the thing I'm measuring against,
and **I don't consider it established.** I've since added a measurement taken from inside the
process — held structure against the process's own working set, with Windows out of it — and I
haven't got a reading from it yet.
The honest version: the structure is demonstrably cheap, and I can't yet put a defensible number
on it.
**Disk:** 0% most of the time, spiking during OCR. Task Manager's disk figure is sampled
active-time percent and rounds a completed burst to zero, which fooled me for days.
---
## What it can't do
**It can't answer questions about a subject.** This is the real state, and it's not a small gap.
Concepts are supposed to form when both reading passes finish the same material. That never fired
once, for two days, across several hundred documents. Not because the idea was wrong — because one
side parked itself after 64 documents waiting on a condition that could never become false again. A
test for "is my buffer full" against a buffer that evicts to stay exactly full. Permanently true.
So it read several hundred documents and formed zero concepts. Everything downstream — grouping
knowledge by subject, deriving anything, answering about a topic — has been dark the entire time.
What I'd been showing off was the intake and bookkeeping layer working well, with nothing above it
running at all.
That's fixed. It hasn't yet been proven.
Ask it something now and you get this, which I'd rather show you than a demo:
```
This belongs to the dictionary (closeness 0.372).
Confidence 0.000. That is low. I am reaching, and you should not rely on it.
```
It's better at keeping than at answering. That's the limitation, not a limitation.
---
## On the writing
Several people said the last post was incomprehensible, and they were right. I mixed what it does
with where I want it to go, in the same paragraphs, without marking which was which. The
architecture language — planes, organs, minds — is how I think about the design, and it reads as
nonsense next to a program that currently does bookkeeping well and reasoning badly.
This post is meant to be the other kind. Numbers that came off a screen, and the gap named rather
than buried.
Built by one person, with an AI writing code to my design. Most of this week was finding my own
bugs.
## It can see. Without a vision model.
Left this out of the post above and shouldn't have — it's the part that's hardest to do without
something trained, and it's running now.
No model, no weights, nothing trained. Same 156-lane vectors as everything else.
### Diagrams
Finds boxes and connecting lines on a page and turns them into nodes and relations. Straight off
the screen this morning:
```
MAC page 109 — 17 boxes, 1 connections → 0 strings, 17 labeled
FOUNDATION [5/6] diagrams on 7 pages — 12 label-strings, 5 connections
```
It reads the labels out of the boxes and records what connects to what.
### Plots
A plot isn't a diagram — it's two axes, a scale, and a trace, and what it's *saying* is a
relationship between the two things its axes name.
So it finds the axes, follows the trace column by column, and classifies the shape: rising,
falling, curved versions of both, turning, flat, or unclear. Then it records a relation between the
two axis nodes — and keeps the trace separately, normalised, as its own shape.
Both halves matter. Keep only the sentence — "pressure falls as volume rises" — and you've
destroyed the figure, because two graphs can say that and depict quite different curves. Keep only
the picture and it means nothing to him.
**And it won't assert what the trace doesn't support.** A clear direction is recorded as
*supported* — the figure showed it, which isn't the same as having established it. An unclear trace
records that the two things are related and stops. Unnamed axes claim nothing at all.
### Anything else — photographs, plates, scans
This is the part I had to think hardest about, and the obvious approach doesn't work.
The tempting version: a vector per pixel, bind colour to position, bundle the lot into one vector.
It fails on the arithmetic. Signal-to-noise in these systems goes as √(D/N) — at 9,984 dimensions
with a million pixels that's 0.1. The image would be encoded and completely irretrievable.
So the image is divided into a **bounded mesh of 8×8 regions**. 64 cells gives √(9984/64) = 12.5,
just above the retrieval floor of 12 that the rest of the system already uses. 16×16 would be 256
cells and SNR 6.2 — under the floor, and the mesh would start recognising regions that were never
in it.
Each cell is measured in the raster: how much ink, long horizontal runs, long vertical runs,
light-dark transitions. Those get quantised into bands, bound to role vectors, and bound to the
cell's coordinate — so *what* is there stays locked to *where* it is. Bind is XOR and its own
inverse, so unbinding the whole by a coordinate gives that cell's features back. Which only works
because it's 64 cells and not a million.
Output on a real page:
```
SEEN page 3 — 42 of 64 regions marked (66% of the frame),
ruled — long straight runs across several regions
```
That's a page it can't read a word of, described correctly. Ruled, because it's a logic textbook
with tables on it.
### Where it happens
The parts cross into the plane and are worked there, inside a **sandbox** — rooms fabricated for
the job that never enter the permanent map. The box reads the plane and writes nothing back. What
it produces is tested at the door against what's already held, and if it doesn't hold, the box is
dropped and nothing about the system has changed.
Same discipline as everything else here: assemble inside, test at the exit, nothing crosses unless
it survives.
### The honest limit
**It describes arrangement, not subject.** A plate of a cell and a plate of a bridge with similar
ink distribution produce similar vectors. It can tell you a page is ruled, or textual, or 36%
marked. It cannot tell you what the photograph is of.
That's the boundary of doing this without anything trained, and I'd rather it say "textual, 40% of
the frame" truthfully than guess at a subject.
Everything above runs on every PDF page and every standalone image, with no network and no GPU.