Frame 01 · The failed model

I tried to build an AI I could understand. It failed.

A readable symbolic bottleneck made a small model worse: the ordinary control won 85.4% of 179 blind comparisons. So I stopped polishing explanations and built a test for whether they actually cause the answer.

Measured failure · three seeds · blind evaluation

179 blind comparisons 85.4% dense control preferred 0 benchmark parity claims

Archive print · Raphael Khalid

01 / the failure

The readable model lost the plot.

Two matched 29.5M-parameter models differed only in their internal state. Forcing one through inspectable symbols damaged story quality and entity tracking.

Held-out story · discrete modelidentity failure
Anna has a new toy. It is a kite. Soon it becomes a balloon, then a flag, a drum, and finally a trumpet.
The grammar survives. The subject does not.

02 / the harder test

Does the answer depend on the explanation?

Erase a real reason: the answer should break. Change an unused note: it should not move.

Readable tracehidden shortcut
numbers2 · 4 · 6
claimed operationsum → 12
unused noteconfidence 0.98
answer12
not attacked
Load-bearing recordnamed steps only
typed inputs2 · 4 · 6
checked operationsum → 12
unused noteconfidence 0.98
answer12
not attacked

They look identical. Attack them.

Illustration, not a trained-model result. The matching synthetic audit passed across five seeds.

03 / what survived

Three results changed the design.

01 / compose

Reuse parts, not answers.

21/21 typed compositions · retrieval 0/21
02 / identity

Names need identities.

25/25 scoped checks survived renaming and reordering
03 / causality

Reasons must carry results.

ledger-only 100% · decorative trace 0%

04 / evidence, not aspiration

Built—and not built.

Working now

  • A typed compiler with 210 tests, a browser front end, and a first CPU runtime.
  • Matched models trained across three seeds.
  • Reproducible causal, identity, and composition probes.

Not established

  • No trained typed-ledger coder.
  • No public coding benchmark.
  • No 27B-model comparison.

05 / the bet

Make the reasoning impossible to hide.

Next: train the ledger and let a matched flat baseline try to beat it.

Scope: This is an executable surrogate and causal-audit testbed—not a trained coding model, not a public benchmark result, and not evidence of parity with a 27B model.

Frame 02 · Latest research run

research run

Latest run, controls, and conclusion.

This panel summarizes the latest checked-in run and the evidence used to choose the next experiment.

completed · 3 seeds

typed state mediation / corrected smoke

This run checks structured state, constrained generation, interventions, and checkpoint recovery. It does not show that the model can reason.

100/100updates
6/48typed constrained
0/48hard mediation
RTX 4060 · checkpoints round-tripped
NULLRaw unconstrained generation solved 0/48 in both arms.
CONTROLThree 16-task oracle checks passed 16/16.
NEXTKeep IR/backend work paused until the preregistration gate.

Data contract: add a fresh Autoresearcher export at data/autoresearcher.json and this panel will show the latest run. Credentials and model weights do not belong in the site.

Frame 03 · Researcher Score

How the score is calculated.

The score rewards progress, the final result, useful variety, and a clean record. The formula is fixed before a run starts.

= 100 × × (0.60 × + 0.20 × + 0.15 × + 0.05 × )
1 · baseline

HumanEval+ is the capability check. The deterministic null scored 0/164. That establishes a floor, not T or Q.

2 · landscape runs

Each test instance has 16 or 20 dimensions. Every proposal records a score, an evaluation cost, and an archive niche. The controller also checks the latest 16 proposals.

3 · normalize

Best result over time

For each instance, compare the best result with the measured starting point and the exhaustively verified optimum. Clip that value to 0–1 as q(t).

4 · make components

T, Q, D, and V

T uses the final q(1). Q compares archive quality with the ideal archive. D uses the whole progress curve. V checks valid and non-duplicate proposals.

5 · apply the gate

Calculate R

If G passes, apply the fixed weights above. If it fails, R is zero and the run is not promoted.

Where T and Q come from: Experiment 16 is not a “16-bit” input to this formula. It is a separate HumanEval+ null. T and Q come from the scored AR1/AR2 landscapes: T is the final normalized result, and Q is the quality of the archive of different solutions.

Frame 04 · Compiler playground

Edit Raly code and see compiler errors immediately.

This is the compiler in the browser, built with and running inside this page. The code stays in your browser. Errors update as you type and underline the relevant characters.

The playground includes the lexer, parser, name resolver, type checker, and diagnostic renderer from the command-line compiler. Try removing one item from the opening capacity example.

raly, 286KB, running in this tab open full size ↗

Frame 06 · What it catches

The compiler detects when a vector exceeds its measured capacity.

These systems can store several items by adding their vectors. Beyond a measured limit, retrieval becomes unreliable even though the operations remain valid and the tensor shapes still match. A conventional runtime does not report an error.

Raly tracks the number of superposed items. In this example, the compiler uses a measured capacity of 31 and reports both the source of that bound and the width needed for 40 items.

The block on the right is copied from compiler/crates/raly/tests/ui/capacity-exceeded.stderr, which is checked character for character on every build. The playground above prints the same thing, from the same code: it is the file it opens with.

raly check capacity-exceeded.raly
error[RALY5001]: this bundles 40 items into a space that holds 31
 --> capacity-exceeded.raly:9:5
  |
9 |     bundle(
  |     ^^^^^^^ 40 items superposed here
  | ...continues to line 15
 ::: capacity-exceeded.raly:3:1
  |
3 | space Small = MAP[1000]
  | ----------------------- `Small` holds 31 items
  |
  = note: 31 is the capacity of `Small` at dimension 1000,
          measured at 95% retrieval in experiments/04_capacity
  = note: past capacity, cleanup returns the wrong atom and
          accuracy degrades towards chance without anything
          failing at run time
  = help: superpose fewer items, or declare `Small` at
          dimension 1247, or 2048 for a power of two

error: 1 error
The capacity of 31 is measured. It comes from experiments/04_capacity, where retrieval stays above 95% at thirty-one items and falls below it at thirty-two. A literature summary put the figure near ten.

Frame 07 · The annotation

A type can describe what a vector contains.

Vec[Concepts; load 3; roles {Subject, Verb, Object}]
  • ConceptsWhich space this vector belongs to. That fixes its width and its family, so vectors from a different space cannot be mixed in by accident.
  • load 3How full it is. Three things are in the bag, and the compiler knows the bag's limit, so it can tell you when a fourth will not fit.
  • roles {…}Which slots are filled is fixed at compile time. What goes in each slot is decided when the program runs.

When the type lists the roles, a function signature describes part of what the vector represents. That information is available without running the model or training a separate probe.

Compile-time dimension checking is not new; Dex, Futhark, and F# already provide related mechanisms. Interpretable-by-construction modeling is also an established area that includes concept bottleneck models, sparse transformers, and KANs. Raly's narrower experiment is to put VSA-specific structure in the .

Frame 08 · How it works

The compiler runs every front-end pass and reports the errors together.

raly check runs every pass every time. No pass is allowed to stop the next one, so a typo does not hide an unknown name and an unknown name does not hide a capacity error. You receive a combined list in source order.

sourcea .raly file
lexany bytes at all become tokens, and it never panics
parsehand-written, recovers from bad syntax, covers the whole file
resolveworks out which definition every name points at
typecheckfour properties, four small solvers

width tracked as a unit of measure, so a mismatch prints the leftover ratio instead of the words "unification failed"
family is a short fixed list, so MAP[1024] and FHRR[1024] stop being the same type
how full is a range of whole numbers over measured capacity: bundle adds, bind multiplies, cleanup drops back to one
slots use , so taking out a slot the vector never had is a compile error

silent bundle.py
import torch

D = 1000
codebook = torch.sign(torch.randn(1000, D))

scene = torch.zeros(D)
for i in item_ids:          # 40 of them
    scene += codebook[i]    # add it to the bag

# No exception. Shapes correct throughout.
# What you read back is no longer what you
# put in, and nothing anywhere says so.
caught capacity.raly
space Small = MAP[1000]

fn everything(...) -> Vec[Small] {
    bundle(a, b, c, /* … 40 items … */)
}

error[RALY5001]: this bundles 40 items
into a space that holds 31

// This is a golden test. The exact text
// above is asserted on every build.

Frame 09 · Experimental results

These numbers come from experiments in this repository.

Each result is linked to its methods and limitations. Where applicable, the experiments define failure criteria in advance, report a null or baseline, and verify headline numbers with a second calculation. Negative results are included.

04 · capacity

Thirty-one items at width 1000.

Retrieval stays above 95% up to thirty-one items bundled into a width-1000 vector, roughly three times a literature baseline. Four widths were measured; this is the number the compiler prints.

experiments/04 →
07 · retrieval cost

Averaging passages into one vector reduced retrieval accuracy.

On BEIR scifact, mean-pooling eight passages drops recall from 0.877 to 0.619. A max-scoring control attributes about 76% of the loss to averaging itself; doubling nominal width does not remove the cost.

experiments/07 →
06 · discrete core

The discrete bottleneck reduced top-1 accuracy by about three points.

At matched parameters, forcing the middle through 1,024 symbols moved top-1 accuracy from 0.8383 to 0.8065. Larger codebooks improved both accuracy and role prediction in this synthetic experiment.

experiments/06 →

What the 1,024 symbols add over the controls

We measured how well a symbol predicts whether the character it fired on belongs to a premise, a working step, or the answer. Three ways of guessing, on the same text:

how you guess the rolegets it rightover the floor
always say the commonest one0.5801the floor
look at the raw character, no model0.6314+0.051
look at which of the 1024 symbols fired0.6640+0.084

The symbols beat the raw-character control by +0.033. This is the additional predictive signal associated with context-dependent code selection. Reproduce the comparison with experiments/06_discrete_core/leakage.py.

The full findings, including the negative result on this project's own idea, live in the repository. All experiments →

Frame 10 · Overnight research

What the coding experiment shows.

On generated repair tasks, typed legality and public search raised the learned sketch from 52.1% raw pass to 89.6% full-system pass. The deterministic null also reached 89.6%. A state-only controller changed 50.0% of raw decisions when state was removed. These are synthetic Python results, not evidence from the Raly compiler or a public coding benchmark. The next checks are EvalPlus HumanEval+, MBPP+, BigCodeBench-Hard Complete, and a later LiveCodeBench sample. Read the audit →

Frame 11 · What exists

The front end works; there is no execution backend yet.

The items marked as missing have not been implemented.

  • Errors that point at exact byte ranges, with a primary and secondary location, separate note and help lines, and stable codes you can grep for. The text is asserted character for character.
  • Lexer that turns any input at all, including arbitrary bytes, into tokens without panicking.
  • Parser written by hand, recovers from bad syntax, and produces a tree that covers the whole file.
  • Name resolution with two namespaces and proper scopes. Using a name before it is defined gets its own message. Suggestions stay quiet unless they are confident.
  • Type checking for all four properties: width, family, how full, and which slots. 210 tests, zero warnings.
  • Browser playground: the whole front end as 286KB of WebAssembly, the capacity error live, no install.
  • ·Code generation does not exist. raly checks programs; it cannot run them.
  • ·Ralytable itself is not built. What exists is the 6.4M-parameter model the second demo takes apart.

Limitations

  • The demo model cannot reason. It is a 6.4M-parameter toy trained on 4,042 synthetic word problems; it formats arithmetic nonsense. The demo shows structure, not capability.
  • The overnight coding result is synthetic. Generated integer-list, Python, and repository-shaped tasks are not general coding or a public benchmark.
  • Raw and verified scores differ. Public search can repair a weak learned proposal, and the deterministic null can match the final score. They are reported separately.
  • One result is still missing. The Raly compiler type-checks but has no IR, code generator, or runtime backend. The overnight Python harness did not call it.
  • The public destination is explicit. HumanEval+ is a disclosed diagnostic scoreboard, MBPP+ the cleaner cross-benchmark check, then BigCodeBench-Hard Complete and a later LiveCodeBench freshness audit. No public result is claimed here.
  • The older findings are bounded. Small corpora, seeds, encoders, and mean-pooling conditions describe those experiments, not every model or dataset.