# PRISME v1 — frozen architecture specification (Phase 1, 2026-10-29) Notation: prefix `x_{1:t}`, backbone residual stream `H_t = B_phi(x_{1:t}) ∈ R^{t×d}`, `h_t = H_t[t]`. Workspace width `w`, `M = 16` slots, editor blocks `L_w = 2` (shared weights), hard cap `R_max = 8`. ## Backbone (`prisme/backbone.py`) Pre-norm causal decoder: RMSNorm → GQA attention (RoPE θ = 10⁴, head dim 64) → RMSNorm → SwiGLU; tied input/output embeddings; one final RMSNorm. `logits = E · RMSNorm(h)`. Exact backbone counts match the brief for the three configurations (`results/tables/param_counts.json`). ## Source bank and workspace initialisation (`prisme/model.py`) `ĥ = RMSNorm_bank(H)` (a dedicated norm, d parameters, added for numerical hygiene — see DECISIONS D2), `K = ĥ W_K`, `V = ĥ W_V` (read-only, causal: query t reads keys 1..t only), `z_t = P ĥ_t`, `S0[j] = e[j] + z_t` for j = 0..15; S is re-initialised at every position (no cross-token memory). ## Action catalog (`prisme/workspace.py`) `SINGLE_0..15`, `PAIR_0_1, PAIR_2_3, …, PAIR_14_15`, `STOP` = 25 actions (24 nonterminal). STOP is absorbing. ## Shared sparse editor (`prisme/editor.py`) Active queries `x = S[I(a)] + ctx_proj([step/R, remaining/R, k/2])`. Each of the two shared blocks: (1) RMSNorm → multi-head cross-attention of the active queries to the bank (q, o projections only; the bank is already in width w) with the strict per-query causal mask; (2) RMSNorm → multi-head attention of the active queries over all M slots of the **pre-write snapshot** (same norm applied to the snapshot); (3) RMSNorm → SwiGLU. Write: `δ = proposed − S[j]`, `δ_c = δ · min(1, c / max(RMS(δ), ε))`, `η = η_max σ(gate([S[j]; proposed]))`, `S'[j] = S[j] + η δ_c`. Non-selected slots are returned bitwise unchanged (one-hot scatter from the same snapshot ⇒ pair writes are order-independent). Defaults: η_max = 0.25, c = 1 (untested research values). ## Value controller (`prisme/controller.py`) Target-free features: `u = f(z_t, step, remaining)` (one SwiGLU MLP per state), per action `h_a = SiLU(u + W_s s_a + k_emb[k(a)])` with `s_a` the mean of the slots in I(a); heads → `ĝ, ĉ, log σ̂, harm`. `Q(s,a) = ĝ − λ c(a) − κ σ̂`, `Q(STOP) = 0`, greedy argmax, STOP when max Q ≤ 0. `c(a)` is the analytic ops cost of the action relative to the backbone ops/token (`prisme/flops.py`), not a learned quantity. ## Differential readout and exact bypass (`prisme/readout.py`, `prisme/model.py`) `r(S, z) = Σ_j softmax_j((W_q z)·(W_k S_j)/√w) S_j`; `Δ = U (r(S_final, z) − r(S0, z))`, U = 0 at init; `h_corr = h + Δ`. `max_budget = 0` ⇒ backbone head returned without allocating slots (explicit branch); positions with zero executed edits also bypass the readout. Identity is bitwise (tests 02–04). ## Causal / cache contract (`prisme/cache.py`, `prisme/generation.py`) Separate per-request caches for backbone KV and bank K/V; the editor never writes to H, K, V, z; incremental decoding equals full-prefix recomputation within 1e-4 (tests in `tests/integration/`). ## Parameter accounting Implemented workspace+controller: 2,631,173 (103M) / 10,505,221 (459M) / 21,655,813 (1.18B) versus the brief's 3,088,260 / 12,336,900 / 25,779,844. The brief's three numbers are reproduced exactly by `4dw + Mw + 17w² + 6w f_w + 15.5w + 4`; the implementation has `10w²` square projections instead of `17w²` (no K/V re-projection of the bank inside the editor, no value projection in the readout, leaner controller) and a few extra vectors (bank norm, context projections, k-embedding). See DECISIONS D3.