Variable binding via slot cells — the first attempt
Decision 0014: Variable binding via slot cells — the first attempt
Date: 2026-05-24 Status: Accepted Builds on: ADRs 0001–0013
Context
Through ADR 0013 we triple-confirmed something the architecture has been telling us since ADR 0008: the substrate has no native mechanism for variable binding. Context cells (ADR 0012) memorize specific 4-token sequences. Approximate matching (ADR 0013) softens that to “exact match with soft edges” — still no generalization.
What’s missing is the ability for a cell to hold a role — to represent “operand-1” or “operand-2” temporarily, with the concrete value filled in from the current observation. With that primitive, a single cell could learn the abstract pattern [OPERAND, +, OPERAND, =] and produce predictions parameterized by the bound values.
This ADR introduces that primitive. A fifth cell type — SLOT — has templates with explicit wildcard positions. When a slot cell’s fixed positions match the observed window, the wildcard positions are filled with whatever happens to be there, and the cell’s preference for the next-token output is indexed by those bound values. The cell effectively learns a multi-dimensional function: (operand_a, operand_b) → predicted_answer.
Honest scoping again: this ADR enables structured memorization — the system learns a tabular function indexed by bound values. It does not produce symbolic arithmetic. Untrained operand pairs (e.g., 5+4 when only sums up to 5 were trained) will produce no useful prediction unless additional inductive structure is introduced. What we will check empirically: does the slot-cell mechanism enable generalization to commuted trained pairs (training 1+2=3 but not 2+1=3) — a minimum test of whether role-binding gives any real abstraction.
Decision
Fifth cell type — SLOT
Add SLOT = 4 to the cell-type constants. Default allocation puts a fraction (slot_cell_fraction, default 0.1) of the cell pool into this type. The remainder splits among the existing four populations as before.
Slot template structure
A slot cell’s template is a tuple of K elements. Each element is either:
- A token index — a fixed position that must match the corresponding window slot exactly.
- The sentinel
SLOT_WILDCARD = -1— a wildcard position that matches any token and records the bound value.
For the arithmetic test, slot cells start with the template [WILDCARD, "+", WILDCARD, "="] — wildcards at the two operand positions, ”+” and ”=” fixed. This template structure is the one architectural prior this ADR introduces: the system is told “expect operands in positions 0 and 2, surrounded by + and =.” Discovering the wildcard structure from data is a separate problem (deferred).
Per-cell binding preferences
Each slot cell stores a dictionary slot_prefs: dict[tuple[int, ...], np.ndarray]. Keys are tuples of bound wildcard values (e.g., (1, 1) for the binding “operand-1=1, operand-2=1”). Values are preference vectors over the vocabulary (length n_tokens).
When the cell’s template matches the window:
- Extract the bound values from the wildcard positions.
- Look up
slot_prefs[bound_values](initializing to zeros if not present). - The cell’s contribution to output is
activation × slot_prefs[bound_values][t]for each token t.
Match-and-bind during observation
The match check in _apply_context_match_boost is extended for slot cells: a slot cell matches when all fixed positions agree with the window. Wildcards always match. The match fraction is 1.0 for a successful match; the existing approximate-matching sharpness does not apply to slot cells (which are by design exact-on-fixed-positions).
On match, the cell receives the full activation boost (same CONTEXT_MATCH_ACTIVATION_BOOST), and the bound values are stored as the cell’s current_binding attribute.
Learning rule for slot cells
When a slot cell matches the window before some observation T, and then the next observation T+1 = X arrives, the bound preference is reinforced:
slot_prefs[bound_values][X] += learning_rate · activation
This is the standard reinforcement rule, just indexed by bound_values rather than applied to a flat per-cell preference vector.
Generation contribution
In generate(), after the context-match boost is applied (now including slot cells), each matched slot cell contributes to the score via its bound-preferences lookup:
score[t] += slot_cell.activation × slot_cell.slot_prefs[binding][t]
This is in addition to the contributions from other cell types’ regular preferences. Cells whose templates don’t match the window contribute nothing through slot mechanics.
Disabling
slot_cell_fraction = 0.0 disables slot cells (the v0.12 four-cell-type architecture is recovered). Default is 0.1 — modest, since slot cells are powerful and a small population goes a long way.
Architectural prior — what’s hand-coded vs learned
This is the first ADR that introduces a significant hand-coded prior: the wildcard positions in slot-cell templates. For arithmetic specifically, we tell the system in advance that “operands appear at positions 0 and 2.” A future ADR could attempt to learn this structure (e.g., by tracking which positions vary most across observations and marking those as wildcards), but that’s an open problem.
This is an honest concession. The original Reverie sketch wanted “intelligence from observation alone,” and slot cells with hand-coded wildcards weaken that claim. The justification: this is the smallest deviation that lets us probe the architectural ceiling on symbolic reasoning. If even with this prior the system can’t generalize to commuted pairs, we know the ceiling is below variable binding. If it can, we’ve made real progress and the next step (learn the wildcard structure) becomes worth attempting.
Empirical probes
These have tests in tests/test_slot_cells.py:
- Slot cells with
[*, +, *, =]templates correctly memorize arithmetic facts. After training on the standard 8-fact set, all 8 trained queries produce the correct answer. - Commutation generalization (real test of variable binding). Train on a subset of facts (e.g., only
a+bwherea ≤ b). Test on the commuted complements (a+bwherea > b— untrained). With variable binding, the system should retrieve the correct answer only if it has learned the operands-as-roles abstraction, since(a, b)and(b, a)are different bindings. - All prior 99 tests continue to pass under the default
slot_cell_fraction = 0.1.
Expected findings (predictions before running)
The most likely outcome:
- Memorization works — slot cells can store the (a, b) → answer mapping just like context cells, possibly more efficiently (one cell per template structure rather than per exact template).
- Commutation doesn’t generalize without explicit symmetry assumption — the binding
(1, 2)and(2, 1)are distinct dict keys; learning one doesn’t transfer to the other. - Honest conclusion: variable binding as implemented here gives structured memorization, not abstract operations. Closing that further gap would require either (a) explicit commutativity priors (symbolic) or (b) operator-cells that learn the operation independently of the operands (genuinely abstract, harder still).
If the commutation test fails, this ADR validates the deeper limit: this substrate, even with explicit role binding, doesn’t naturally extract operations. That’s a real architectural ceiling, worth knowing precisely.
Open questions deferred
- Learned wildcard structure. The system should discover which positions are variable from observation, not be told.
- Commutativity as a learned property. Could the system observe that swapping operands gives the same answer and generalize that pattern itself?
- Operator cells. A cell that represents the ”+ operation” abstractly, parameterized by operands. Genuinely closer to symbolic computation.
- Larger and richer slot templates. Currently a single wildcard structure per cell. Could cells learn to compose templates?