|
| 1 | +// SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | +// SPDX-FileCopyrightText: 2025-2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk> |
| 3 | += Cluster C2 wave 2b (VM memory / stack / port / control) — four-gate evidence (captured 2026-06-05) |
| 4 | +:toc: macro |
| 5 | + |
| 6 | +[IMPORTANT] |
| 7 | +==== |
| 8 | +*The ledger's premise for this wave was wrong, and re-decomposition overturned |
| 9 | +it.* Wave 2b was scoped as "needs an array/linear-memory ABI." Reading the |
| 10 | +actual opcode sources shows the VM's memory, stack, and port buffers are NOT |
| 11 | +arrays in the brain — `VmState.res` stores every one of them as *string-keyed |
| 12 | +dict entries* (`_mem:0`, `_s:0`, `_pin:port`, ...). That dict is host-side STATE |
| 13 | +(the senses). The pure-integer brains are all SCALAR: additive value transforms, |
| 14 | +pointer arithmetic, and branch predicates. So wave 2b needs *no* array ABI — |
| 15 | +it is the established scalar recipe. Toolchain: AffineScript compiler |
| 16 | +`_build/default/bin/main.exe`, Deno 2.8.2. |
| 17 | +==== |
| 18 | + |
| 19 | +toc::[] |
| 20 | + |
| 21 | +== Summary |
| 22 | + |
| 23 | +[cols="2,2,1,1,2,1",options="header"] |
| 24 | +|=== |
| 25 | +| Kernel | Opcodes | G1 | G2 parity | G3 | G4 assail |
| 26 | +| `VmMemory` | LOAD, STORE | OK | 486/486 | n/a (transform) | clean |
| 27 | +| `VmStack` | PUSH, POP | OK | 28/28 | n/a (transform) | clean |
| 28 | +| `VmPort` | RECV, SEND | OK | 298/298 | n/a (transform) | clean |
| 29 | +| `VmControl` | IF_POS, IF_ZERO, LOOP | OK | 756/756 | n/a (predicate) | clean |
| 30 | +| *Total* | *9 opcodes* | *4/4* | *1568/1568* | *n/a* | *4/4 clean* |
| 31 | +|=== |
| 32 | + |
| 33 | +== The re-decomposition that dissolved the array-ABI blocker |
| 34 | + |
| 35 | +Each opcode manipulates host-side state, but the integer brain is scalar: |
| 36 | + |
| 37 | +[cols="1,3,2",options="header"] |
| 38 | +|=== |
| 39 | +| Opcode | Source semantics | Scalar brain (the wasm) |
| 40 | +| LOAD | `reg += memory[addr]` / `reg -= memory[addr]` | additive `reg ± mem` (host supplies `mem`) |
| 41 | +| STORE | `memory[addr] += reg` / `-= reg` | additive `mem ± reg` |
| 42 | +| PUSH | `stack[sp]:=reg; sp++; reg:=0` | pointer `sp+1`, register clear `0` |
| 43 | +| POP | `sp--; reg:=stack[sp]; stack[sp]:=0` | pointer `sp-1` |
| 44 | +| RECV | `reg += port_in[ptr]; ptr++` | additive `reg ± val`, pointer `ptr±1` |
| 45 | +| SEND | `port_out[ptr]:=reg; ptr++` (inv writes 0) | pointer `ptr±1`, slot clear `0` |
| 46 | +| IF_POS | run then/else by `testReg > 0` | predicate `v > 0 -> 1/0` |
| 47 | +| IF_ZERO| run then/else by `testReg == 0` | predicate `v == 0 -> 1/0` |
| 48 | +| LOOP | `while exitReg != 0 && iters < max` | continuation predicate + `iters+1` |
| 49 | +|=== |
| 50 | + |
| 51 | +The arrays (`stack`, `memory`, port buffers) and the register dict are the |
| 52 | +*senses* — host-owned `VmState` dict slots. The host performs every array |
| 53 | +get/set; the wasm computes only the next pointer, the accumulated value, or the |
| 54 | +branch decision. "The integer IS the register / pointer / predicate." |
| 55 | + |
| 56 | +*Reversibility is migrated as explicit round-trip exports* (the headline gate): |
| 57 | +`load_roundtrip == reg`, `store_roundtrip == mem`, `sp_roundtrip == sp`, |
| 58 | +`recv_acc_roundtrip == reg`, `recv_ptr_roundtrip == ptr`, |
| 59 | +`send_ptr_roundtrip == ptr`. IF_POS/IF_ZERO/LOOP carry no value round-trip — |
| 60 | +their Janus reversibility is host orchestration (the reverse run applies the |
| 61 | +same predicate to the *exit* register and runs the chosen branch reversed); the |
| 62 | +brain is the shared predicate. |
| 63 | + |
| 64 | +== No-kernel files (host-side senses, faithfully classified — not migrated) |
| 65 | + |
| 66 | +[cols="2,3",options="header"] |
| 67 | +|=== |
| 68 | +| File | Why no integer brain |
| 69 | +| `Call.res` | Pure orchestration: runs the body instructions forward / reversed-and-inverted. No value transform. |
| 70 | +| `CoprocessorCall.res` | *Tombstone* — never implemented; superseded by terminal SEND/RECV + VM Tier-4 Send/Recv (see the file's own header). Nothing to migrate. |
| 71 | +| `State.res`, `VmState.res` | The state container itself (the senses): `dict<int>` slot accessors + serialise (string-gated). No brain. |
| 72 | +| `SubroutineRegistry.res` | name -> `array<Instruction.t>` registry; orchestration container. |
| 73 | +| `VmStateCoprocessor.res`, `InstructionCoprocessor.res` | Coprocessor bridges — host-side dispatch; the integer cores they call are the already-migrated opcode brains. |
| 74 | +| `VM.res` | Top-level interpreter loop: sequences opcode execute/invert over the state dict. Orchestration; the per-opcode brains are migrated here + in waves 1/2a. |
| 75 | +|=== |
| 76 | + |
| 77 | +== Gate detail |
| 78 | + |
| 79 | +* *G1 compile* — `main.exe compile <k>.affine -o <k>.wasm` → WASM for all 4 |
| 80 | + (VmMemory 346 B, VmStack 243 B, VmPort 508 B, VmControl 299 B). |
| 81 | +* *G2 parity* — `parity.mjs <k>.config.mjs` → 1568/1568 over the i32 domain |
| 82 | + `{INT_MIN, -1e6, -7, -1, 0, 1, 7, 1e6, INT_MAX}` (Cartesian per arity). Each |
| 83 | + oracle independently re-derives the original `.res` value transform. |
| 84 | +* *G3 boundary* — n/a for all 4. These are numeric transforms / branch |
| 85 | + predicates with no discrete value↔integer encoding table; the G2 round-trip |
| 86 | + against the independent oracle is the faithfulness check (same disposition as |
| 87 | + the wave-1/2a value-transform kernels). |
| 88 | +* *G4 assail* — 0 findings across all 4. Predicates use boolean fall-through |
| 89 | + (`if cond { 1 } else { 0 }`) and the LOOP guard uses an out-of-band `return 0` |
| 90 | + on the `exit_val == 0` early exit; there is no enum decoder, so PA-AFF-001 |
| 91 | + does not apply. |
| 92 | + |
| 93 | +== Cluster C2 — COMPLETE |
| 94 | + |
| 95 | +With wave 1 (Add/Sub/Negate/Noop/Swap/Flip/Xor/Rol/Ror/And/Or + Instruction |
| 96 | +taxonomy), wave 2a (Mul/Div), and wave 2b (Load/Store/Push/Pop/Recv/Send/IfPos/ |
| 97 | +IfZero/Loop), every reversible-VM opcode with a separable integer brain is |
| 98 | +migrated and four-gate verified. The remaining C2 files (Call, CoprocessorCall, |
| 99 | +State, VmState, VM, SubroutineRegistry, VmStateCoprocessor, InstructionCoprocessor) |
| 100 | +are host-side senses / orchestration with no integer brain, classified above. |
| 101 | +*No array/linear-memory ABI was required* — that blocker was an artefact of the |
| 102 | +coarse triage bucket, dissolved by reading the sources. (The string wall remains |
| 103 | +a separate, genuine compiler gate for the STRING-GATED clusters.) |
0 commit comments