WireValue:
    | null
    | boolean
    | number
    | string
    | readonly (WireValue | undefined)[]
    | { readonly [key: string]: undefined | WireValue }
    | ReadonlySet<WireValue | undefined>
    | ReadonlyMap<WireValue | undefined, WireValue | undefined>
    | Date
    | WireTemporal

A TypeScript sufficient condition for membership of the wire value domain — the values that cross the FFI boundary intact, and the values §5.1 Amendment 7's derived-cutoff relation ranges over (SPEC.md, "structural deep-equality over the shipped wire value domain").

It is JSON — null / boolean / number / string, arrays, plain objects — extended by the four tagged containers the bridge carries: Set, Map, Date and Temporal.*. packages/core/wasm/tagged-types.ts rewrites each of those four into a __causlType-tagged plain object on the way into the value pool and reconstructs the real instance on the way out, so all four are INSIDE the domain, compare element-wise, and round-trip as real instances on both shipped engines.

Read the direction before trusting a tsc verdict. Assignability to WireValue is sufficient for domain membership and is not necessary: everything the type admits is in the domain, and the converse does not hold. It cannot be made to hold in TypeScript. The object arm has to be an index signature — that is what makes the type recursive and what makes it refuse { cb: () => void } — and TypeScript grants an implicit index signature to an anonymous object type or a type alias, but never to an interface or a class:

type      RowA = { id: number }   // assignable
interface RowB { id: number } // TS2322 — identical members, refused
class RowC { id = 1 } // TS2322 — refused

All three are the same plain object at run time and the relation walks all three identically: the shipped content-hash gives new RowC() and { id: 1 } one verdict (packages/core/wasm/content-hash.ts), which is what §5.1 Amendment 8 records as a permitted quotient. So a TS2322 here is a statement about TypeScript's assignability rules, never a statement about the domain — an interface-declared row type is INSIDE it. Adopters who want the check anyway: declare the shape as a type alias, or widen at the use site with a spread. This paragraph exists because an omission is not a denial — a reader who found no disclaimer here would read the refusal as a domain verdict, which is exactly backwards. test/value-domain-open-270.test.ts pins both halves so the type and this text cannot drift apart.

undefined is a member position, never a value. The container arms read WireValue | undefined; the union head does not. That is what admits { a: undefined }, Record<string, T | undefined>, a Set/Map holding undefined, and the hole in [ , 1] — none of which have any spelling this type could otherwise reach, and all of which the shipped relation already places on a verdict it also gives a null-spelled twin it admitted all along. A bare top-level undefined is different: isWireNull collapses it to the NULL wire record before anything structural runs, so it stays out of the head and undefined on its own is still refused. bigint, symbol and function stay out of member positions too — admitting them would leave the recursion excluding nothing, which is the only work the type does.

This is NOT a bound on Graph.input, Graph.derived or Compute, and it must not become one. #270 settled that question: the adopter-facing value domain is OPEN and WireValue names the cutoff/marshal domain only. The decision, and the cost of the alternative, are recorded once in SPEC §15.1's #270 amendment.

The four non-JSON scalar classes — undefined, bigint, symbol and function — sit OUTSIDE WireValue as top-level values (see the member-position remark above for the one place undefined is inside) and are nevertheless admitted at the adopter surface. packages/core/src/value-domain.ts is where that split is implemented: isWireNull collapses all four to the single NULL wire record so the two engines agree on whether a write fires, while the value itself is retained host-side and read returns the real reference on both engines. A closure-valued input reads back under Object.is as the same function it was written with; the coercion #151 shipped went into the cutoff, never into read.

Earlier plans named this constraint JsonRoundtrippable and proposed it as a Node<T> bound. That name is JSON-only, so as a bound it would have refused Set, Map, Date and Temporal — four types both engines already carry correctly — on its first day. WireValue is the corrected name for the domain that actually exists; there is no bound.

WireTemporal for the Temporal.* member's shape.