Parent: #10107 (OpenCode v1.18.30). This is the bootstrap wall behind Cannot read properties of undefined (reading 'size') in every real OpenCode command (run, models, serve, TUI) after #10160 landed.
Repro (2 modules, seconds to compile)
// lib.ts
export const count = (...xs: any[]) => xs.length
export const mergeAll = (...ctxs: any[]) => { const m = new Map(); for (let i = 0; i < ctxs.length; i++) ctxs[i].mapUnsafe.forEach((v: any, k: any) => m.set(k, v)); return { mapUnsafe: m } }
export const mk = (k: string) => ({ mapUnsafe: new Map([[k, k.length]]) })
export const fill = (n: number, f: (i: number) => any) => { const out = new Array(n); for (let i = 0; i < n; i++) out[i] = f(i); return out }
// main.ts
import * as Lib from "./lib"
import { fill, mk } from "./lib"
const other = fill(3, (i) => mk("k".repeat(i + 1)))
console.log(Lib.count(1, 2, 3)) // 3 (ok)
console.log(Lib.count(...other)) // perry: the FUNCTION `(...xs) => xs.length`; bun/node: 3
console.log(Lib.count(0, ...other)) // perry: the function; bun/node: 4
console.log(Lib.mergeAll(...other)) // perry: the function; bun/node: { mapUnsafe: Map(3) }
console.log((Lib as any)["mergeAll"](...other)) // perry: the function
console.log(Lib.mk(...(["zz"] as [string]))) // ok — literal array spread
const m = Lib.mergeAll; console.log(m(...other)) // ok — local alias
console.log(Lib.mergeAll.call(null, ...other), Lib.mergeAll.apply(null, other)) // ok
perry compile main.ts --no-auto-optimize (perry 0.5.1544 + three unrelated fixes, linux-x64): a call on a namespace-import member whose arguments contain a spread of a non-literal array is lowered to the member read alone — the call never happens and the expression evaluates to the function value. Any downstream property read on the "result" then fails ((fn).mapUnsafe is undefined → .size throws), which is exactly what happens in effect's Layer.mergeAllEffect:
internalEffect.map((context) => Context.mergeAll(...(context as any))) // effect/src/Layer.ts:1519, Context is `import * as`
so Layer.merge / Layer.mergeAll produce a wrong context, Context.merge(self, that) later reads that.mapUnsafe.size of a non-context, and OpenCode's AppRuntime (a Layer.mergeAll of ~50 services) dies before its first log line. Verified: a 60-module effect probe with Effect.provide(Layer.mergeAll(a, b)) fails under perry and passes under bun; provideMerge (no spread) works.
Acceptance
Parent: #10107 (OpenCode v1.18.30). This is the bootstrap wall behind
Cannot read properties of undefined (reading 'size')in every real OpenCode command (run,models,serve, TUI) after #10160 landed.Repro (2 modules, seconds to compile)
perry compile main.ts --no-auto-optimize(perry 0.5.1544 + three unrelated fixes, linux-x64): a call on a namespace-import member whose arguments contain a spread of a non-literal array is lowered to the member read alone — the call never happens and the expression evaluates to the function value. Any downstream property read on the "result" then fails ((fn).mapUnsafeisundefined→.sizethrows), which is exactly what happens in effect'sLayer.mergeAllEffect:so
Layer.merge/Layer.mergeAllproduce a wrong context,Context.merge(self, that)later readsthat.mapUnsafe.sizeof a non-context, and OpenCode'sAppRuntime(aLayer.mergeAllof ~50 services) dies before its first log line. Verified: a 60-module effect probe withEffect.provide(Layer.mergeAll(a, b))fails under perry and passes under bun;provideMerge(no spread) works.Acceptance
new Array(n)-built and callback-built arrays).crates/perry/tests/(2-module fixture) plus a unit test in the call lowering.modelsgets past the bootstrap (firstcreating instancelog line) — result to be posted on tracking: OpenCode v1.18.30 — complete native build from real TypeScript (no stripping, no bundle), startup faster than bun #10107.