> **RESOLVED (2026-06-18).** Root cause: `buildPackSliceValue` (`src/ir/lower/pack.zig`) > built the `$` `[]Type` slice as `[]Any` (16-byte elements) — a stale mapping > from before the dedicated `Type` builtin (`.type_value`, 8 bytes) replaced `Type → .any`. > It stored 8-byte `const_type` words into 16-byte slots, so a `[]Type` reader (8-byte > stride) read `[t0, pad, t1, …]`. Fix: build the slice/array as `.type_value` (8 bytes). > Regression test: `examples/0525-packs-pack-as-type-slice-arg.sx`. The stopgap > `type_name` `.unresolved` guard added in 379ed05 was removed (root cause fixed). > 700/0 both gates. # 0143 — A variadic pack passed as `[]Type` across a call is mis-strided (Any-sized backing, Type-sized view) **Symptom** — When a variadic `..$args` pack is forwarded as a `[]Type` *argument* to another function, reading `args[i]` yields the **wrong** element: the backing array is laid out as `[N x Any]` (16-byte `{i64,i64}` slots) but the slice's element type is `Type`/`type_value` (8 bytes), so an 8-byte-strided index read lands on `elem0`, then the *padding* of `elem0` (reads as `.unresolved`), then `elem1`, … — i.e. half-stride reads. Observed (on the flat-memory comptime VM, which is byte-accurate) vs expected (legacy interp, whose tagged-`Value` model is stride-agnostic and reads the right logical element): ``` VM: [i64 string ] legacy: [i64 string bool ] ``` The legacy interpreter masks the bug (it indexes a logical sequence of `Value`s, not bytes). The VM exposes it. This is what makes `examples/0114-types-build-block-convert` read `arg1: ` instead of `arg1: string` once the VM handles `type_name` (it currently bails on the `.unresolved` read — see the guard added in `comptime_vm.zig` `type_name`, commit 379ed05 — so under the fallback it falls back; under `SX_COMPTIME_FLAT_STRICT` it is a hard error). ## Reproduction ```sx #import "modules/std.sx"; inner :: (args: []Type) -> string { s := ""; i : i64 = 0; while i < args.len { s = concat(s, type_name(args[i])); s = concat(s, " "); i = i + 1; } return s; } outer :: (..$args) -> string { return inner($args); } // <-- pack passed as []Type across a call R :: #run outer(42, "hi", true); main :: () { print("[{}]\n", R); } ``` Expected: `[i64 string bool ]`. Actual (VM): `[i64 string ]`. Note the *direct* use (no cross-call) is fine — `walk :: (..$args) { list := $args; … type_name(list[i]) … }` reads correctly. Only forwarding the pack as a `[]Type` **argument** mis-strides. ## Root cause (hypothesis) The pack `$args` is materialised as a `[N x Any]` array (each arg boxed as a 16-byte `Any` — confirmed in the LLVM IR: `array_to_string__AR_3_Any` / `[3 x { i64, i64 }]`), but when forwarded to a `[]Type` parameter the slice is typed with element `type_value` (8 bytes). The slice `{ptr,len}` points at the `[N x Any]` data, so `index_get` with an 8-byte element stride reads garbage. The fix belongs in **lowering**, not the VM: a pack consumed as `[]Type` must either (a) materialise a real `[N x Type]` (8-byte) array by extracting each arg's type tag from its Any box, or (b) keep the slice element type as `Any` and have `type_name`/reflection read the Any's tag (the VM's `type_name` already handles an `.any` arg). Option (b) is likely smaller. Whichever: the slice's element type and its backing array's element size MUST agree. Suspected area: the pack-expansion / pack-as-slice lowering (search `src/ir/lower/` for the `..$args` → slice materialisation and the `[]Type` coercion of a value pack; `pack.zig`). ## Investigation prompt (paste into a fresh session) > A variadic `..$args` pack forwarded as a `[]Type` argument across a call is > mis-strided: the backing array is `[N x Any]` (16B slots) but the slice element > type is `type_value` (8B), so `args[i]` reads at the wrong offset. The legacy > interp masks it (Value-indexed); the byte-accurate comptime VM exposes it > (`examples/0114`, and the minimal repro in `issues/0143-…md`). Fix it in > lowering: make the pack→`[]Type` materialisation agree on element size — either > build a real `[N x Type]` array (extract each Any's type tag) or type the slice > `[]Any` and let reflection read the Any tag (`type_name` already handles `.any`). > Verify: run the repro on the VM (`SX_COMPTIME_FLAT=1 sx run`) and expect > `[i64 string bool ]`; then `examples/0114` must produce `arg1: string` (not > ``) and run HANDLED under `SX_COMPTIME_FLAT_STRICT=1` matching legacy. > Drop the `tid == .unresolved` guard in `comptime_vm.zig` `type_name` once the > root cause is fixed (it was a stopgap so the VM declines rather than emits > garbage). ## Status OPEN. Blocks `examples/0114` from running HANDLED on the comptime VM (Phase 4 legacy-interp retirement). Not a blocker for the other comptime-op ports.