Skip to content

Commit 0cc0f38

Browse files
Phase H.5: array-bounds healing via fold_escape on the index
examples/self_healing_h5.omc — `safe arr_get(a, idx)` and `safe arr_set(a, idx, v)` make out-of-bounds accesses total. Healing formula: healed_idx = ((fold_escape(idx) % arr_len(a)) + arr_len(a)) % arr_len(a) fold_escape pulls the index onto the nearest Fibonacci attractor; modulo by arr_len keeps it in-bounds. Empty arrays return Null rather than error. Deterministic, in-bounds, and lands the access on an attractor index wherever the grid permits. For safe_arr_get([10, 20, 30], idx): idx=999 → fold to 610 → 610 % 3 = 1 → returns 20 idx=-5 → fold to -5 → ((-5%3)+3)%3 = 1 → returns 20 Two new host primitives (safe_arr_get, safe_arr_set) compose the existing fold_to_fibonacci_const helper. The encoder extends the H.4 SAFE_EXPR rewrite to recognize `safe arr_get(...)` and `safe arr_set(...)` call shapes. p_stmt gains a SAFE branch so `safe arr_set(buf, i, v);` works as a bare statement. Five demos, five convergences. Demo 4 is the visual win — a loop reading 8 indices off a 5-element array via safe arr_get. Every output value has φ=1.000. Every OOB read landed on a Fibonacci attractor. Known limit: safe arr_set via the OMC bytecode VM is a no-op because CALL_BUILTIN routes through a synthetic-scope shim that copies array arguments and loses the mutation. Reads compose cleanly through either interpretation path. H.5.1 would add an SAFE_ARR_SET_NAMED opcode pair (same pattern as V.7c's ARR_SET_NAMED) to fix writes. Demo 4 was rewritten to use safe arr_get only, avoiding this trap. README and CHANGELOG updated: - README "What's proven right now" table adds an H.5 row. - README headline bullet adds array-index OOB to the bug-class list and points at h5.omc as the current healer demo. - The phase arc adds H.5. - CHANGELOG gets a full H.5 entry above H.4. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent ccccf51 commit 0cc0f38

4 files changed

Lines changed: 2428 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,61 @@ All notable changes to OMNIcode will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added (Phase H.5: array-bounds healing via fold_escape on the index, 2026-05-14)
8+
9+
🎯 **`examples/self_healing_h5.omc``safe arr_get(a, idx)` and `safe arr_set(a, idx, v)` make out-of-bounds accesses total.**
10+
11+
H.4 made dynamic divide-by-zero safe at the math level (`safe a / b``safe_divide(a, b)` → fold the divisor away from zero). H.5 extends the same pattern to the next obvious bug class: **array-index violations.**
12+
13+
#### The healing formula
14+
15+
For a `safe`-wrapped array access, the encoder rewrites the call to a new host primitive that applies:
16+
17+
```
18+
healed_idx = ((fold_escape(idx) % arr_len(a)) + arr_len(a)) % arr_len(a)
19+
```
20+
21+
`fold_escape` pulls the index onto the nearest Fibonacci attractor; modulo by `arr_len(a)` keeps it in-bounds; the redundant `+ len) % len` handles negative remainders cleanly. Empty arrays return `Null` rather than error — the access stays total.
22+
23+
What this means in practice for `safe arr_get([10, 20, 30], idx)`:
24+
25+
| `idx` | `fold_escape(idx)` | `% 3` | Result |
26+
|---|---|---|---|
27+
| 1 | 1 | 1 | `20` (in bounds, attractor) |
28+
| 7 | 8 | 2 | `30` |
29+
| 999 | 610 | 1 | `20` |
30+
| -5 | -5 | 1 (after sign-fix) | `20` |
31+
32+
Deterministic, in-bounds, attractor-landing where the Fibonacci grid permits.
33+
34+
#### Implementation surface
35+
36+
Adding the new primitive is a ~30-line composition:
37+
38+
- `omnimcode-core/src/interpreter.rs` — two new host builtins `safe_arr_get` and `safe_arr_set`. Both reuse the existing `fold_to_fibonacci_const` helper.
39+
- `examples/self_healing_h5.omc`:
40+
- `is_builtin` recognizes the two new names.
41+
- `call_builtin` dispatches them.
42+
- `collect_defined` adds them to the typo-correction name table.
43+
- `enc_expr`'s `SAFE_EXPR` branch extends to recognize `safe arr_get(...)` and `safe arr_set(...)` call shapes, rewriting to the new builtins.
44+
- `p_stmt` gains a `SAFE` branch so `safe arr_set(buf, i, v);` works as a bare statement.
45+
46+
No new keywords, no new AST nodes — H.4's `SAFE_EXPR` is reused.
47+
48+
#### Five demos, five convergences
49+
50+
- Demo 1 (regression): H.4's `safe a / b` still works — `compute(144, 0) → 144`.
51+
- Demo 2 (baseline): unguarded `arr_get(xs, idx)` — runs only because the demo index is in-bounds.
52+
- Demo 3 (headline): `safe arr_get` with indices `{1, 999, -5, 7}` against a 3-element array. All four reads return finite values; the OOB indices land on attractor positions.
53+
- Demo 4 (loop walking off the end): `i = 0..7` reading from a 5-element array via `safe arr_get`. **Every output value has `φ=1.000`** — every read landed on a Fibonacci attractor.
54+
- Demo 5 (H.4 + H.5 composed): a function that does both a safe array read and a safe division on the result. Survives both a singular divisor and an OOB index in one call.
55+
56+
#### One known limit (logged for H.5.1)
57+
58+
`safe arr_set(VAR, ...)` works under tree-walk but not via the OMC bytecode VM. The bytecode VM routes `CALL_BUILTIN` through a synthetic-scope shim that copies the array argument; the mutation lives in the temporary scope and doesn't propagate back to the caller's variable. The Rust VM solved this same problem in V.7c with `ARR_SET_NAMED` opcodes. H.5.1 would add an `SAFE_ARR_SET_NAMED` variant. Reads (`safe arr_get`) compose cleanly through either path because they return a value rather than mutating a binding.
59+
60+
Demo 4 was rewritten to use `safe arr_get` only, avoiding this trap. The Phase H semantic claim — that out-of-bounds accesses become total — is intact for reads on both interpretation paths.
61+
762
### Added (Phase H.4: `safe` keyword — runtime self-healing as user syntax, 2026-05-14)
863

964
🎯 **`examples/self_healing_h4.omc` — the user can now DECLARE self-healing intent in source code, not just rely on the compiler to detect it.**

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
OMNIcode (OMC) is an experimental programming language built around a single architectural premise: **φ-math (Fibonacci resonance, value-danger, harmonic alignment) is not decoration — it is a decidable, cheap-to-compute substrate the compiler can reason against.** That substrate makes possible two things conventional languages structurally cannot do without external tooling:
66

77
1. **Self-hosting at the back-end level.** The OMC compiler is written in OMC, and the bytecode the compiler produces for its own source is byte-identical to the bytecode the host-language tree-walker would produce. See `examples/self_hosting_v9b.omc``gen2 == gen3` of a real compiler-as-function.
8-
2. **Self-healing at compile time AND runtime.** The compiler can detect a working class of bugs (numeric off-by-one against Fibonacci attractors, identifier typos, dynamic divide-by-singularity, missing braces / parens / semicolons) and rewrite the program — using the language's own φ-math primitives, not a hand-written rule table. See `examples/self_healing_h4.omc`.
8+
2. **Self-healing at compile time AND runtime.** The compiler can detect a working class of bugs (numeric off-by-one against Fibonacci attractors, identifier typos, dynamic divide-by-singularity, array-index out-of-bounds, missing braces / parens / semicolons) and rewrite the program — using the language's own φ-math primitives, not a hand-written rule table. See `examples/self_healing_h5.omc`.
99

1010
This is a research artifact. It is not a production runtime. But the architectural claims above are **demonstrable, reproducible, and run on the binary in this repository.**
1111

@@ -41,6 +41,7 @@ What this is **not**: a fast runtime, a production toolchain, a stable API, a de
4141
| The compiler is a fixed point under self-application | `examples/self_hosting_v9b.omc` | `✓✓✓ ALL THREE FIXPOINTS REACHED` |
4242
| Self-healing across two stages (token + AST), 5 bugs healed in one source | `examples/self_healing_h3.omc` | All four demos converge; `safe(8) → 8` on the integrated case |
4343
| User-declared runtime self-healing via `safe` keyword | `examples/self_healing_h4.omc` | `compute(144, 0) → 144` — runtime crash converted to finite answer on attractor |
44+
| Array-bounds healing — out-of-bounds reads become attractor-landing | `examples/self_healing_h5.omc` | Loop walking 8 indices off a 5-element array; every output has `φ=1.000` |
4445

4546
Run any of these with the binary built from this repo:
4647

@@ -96,6 +97,8 @@ Built on top of the Phase V self-hosting stack. The compiler now uses φ-math to
9697
Token-level repair: missing braces, parens, semicolons. The integrated demo handles **five bugs across two stages** (token + AST) in one source. Output: `safe(8) → 8` on attractor.
9798
- **H.4 — `safe` keyword** (`examples/self_healing_h4.omc`)
9899
User-declared runtime self-healing. `safe count / mod` unconditionally rewrites to `safe_divide(count, mod)` even when `mod` is a variable the static healer can't reach. `compute(144, 0)` returns 144 instead of crashing.
100+
- **H.5 — Array-bounds healing** (`examples/self_healing_h5.omc`)
101+
Extends `safe` to array accesses. `safe arr_get(xs, idx)` rewrites to `safe_arr_get`, which folds the index onto the nearest Fibonacci attractor and modulos by `arr_len(xs)`. Out-of-bounds reads become total, deterministic, attractor-landing finite values. Demo: a loop reading 8 indices off a 5-element array — every value has `φ=1.000`.
99102

100103
The full design rationale, milestone-by-milestone, is in `CHANGELOG.md`.
101104

0 commit comments

Comments
 (0)