diff --git a/.vscode/settings.json b/.vscode/settings.json
index 9e552f3141..e1bf8c926e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -18,8 +18,8 @@
 		// too many overlapping names, easy to import in schema/arktype where we don't want it
 		// should just import as * as ts when we need it in attest
 		"typescript",
-		"./ark/type/api.ts",
-		"./ark/schema/api.ts"
+		"./ark/type/api.ts"
+		// "./ark/schema/api.ts"
 	],
 	"typescript.tsserver.experimental.enableProjectDiagnostics": true,
 	// IF YOU UPDATE THE MOCHA CONFIG HERE, PLEASE ALSO UPDATE package.json/mocha AND ark/repo/mocha.jsonc
diff --git a/ark/attest/__tests__/benchExpectedOutput.ts b/ark/attest/__tests__/benchExpectedOutput.ts
index db78710ffc..40438d5398 100644
--- a/ark/attest/__tests__/benchExpectedOutput.ts
+++ b/ark/attest/__tests__/benchExpectedOutput.ts
@@ -9,25 +9,19 @@ const fakeCallOptions = {
 
 bench(
 	"bench call single stat median",
-	() => {
-		return "boofoozoo".includes("foo")
-	},
+	() => "boofoozoo".includes("foo"),
 	fakeCallOptions
 ).median([2, "ms"])
 
 bench(
 	"bench call single stat",
-	() => {
-		return "boofoozoo".includes("foo")
-	},
+	() => "boofoozoo".includes("foo"),
 	fakeCallOptions
 ).mean([2, "ms"])
 
 bench(
 	"bench call mark",
-	() => {
-		return /.*foo.*/.test("boofoozoo")
-	},
+	() => /.*foo.*/.test("boofoozoo"),
 	fakeCallOptions
 ).mark({ mean: [2, "ms"], median: [2, "ms"] })
 
@@ -35,19 +29,19 @@ type makeComplexType<S extends string> =
 	S extends `${infer head}${infer tail}` ? head | tail | makeComplexType<tail>
 	:	S
 
-bench("bench type", () => {
-	return {} as makeComplexType<"defenestration">
-}).types([176, "instantiations"])
+bench("bench type", () => ({}) as makeComplexType<"defenestration">).types([
+	176,
+	"instantiations"
+])
 
-bench("bench type from external module", () => {
-	return {} as externalmakeComplexType<"defenestration">
-}).types([193, "instantiations"])
+bench(
+	"bench type from external module",
+	() => ({}) as externalmakeComplexType<"defenestration">
+).types([193, "instantiations"])
 
 bench(
 	"bench call and type",
-	() => {
-		return {} as makeComplexType<"antidisestablishmentarianism">
-	},
+	() => ({}) as makeComplexType<"antidisestablishmentarianism">,
 	fakeCallOptions
 )
 	.mean([2, "ms"])
diff --git a/ark/attest/__tests__/benchTemplate.ts b/ark/attest/__tests__/benchTemplate.ts
index 077d49a7ff..e5764f511a 100644
--- a/ark/attest/__tests__/benchTemplate.ts
+++ b/ark/attest/__tests__/benchTemplate.ts
@@ -9,25 +9,19 @@ const fakeCallOptions = {
 
 bench(
 	"bench call single stat median",
-	() => {
-		return "boofoozoo".includes("foo")
-	},
+	() => "boofoozoo".includes("foo"),
 	fakeCallOptions
 ).median()
 
 bench(
 	"bench call single stat",
-	() => {
-		return "boofoozoo".includes("foo")
-	},
+	() => "boofoozoo".includes("foo"),
 	fakeCallOptions
 ).mean()
 
 bench(
 	"bench call mark",
-	() => {
-		return /.*foo.*/.test("boofoozoo")
-	},
+	() => /.*foo.*/.test("boofoozoo"),
 	fakeCallOptions
 ).mark()
 
@@ -35,19 +29,16 @@ type makeComplexType<S extends string> =
 	S extends `${infer head}${infer tail}` ? head | tail | makeComplexType<tail>
 	:	S
 
-bench("bench type", () => {
-	return {} as makeComplexType<"defenestration">
-}).types()
+bench("bench type", () => ({}) as makeComplexType<"defenestration">).types()
 
-bench("bench type from external module", () => {
-	return {} as externalmakeComplexType<"defenestration">
-}).types()
+bench(
+	"bench type from external module",
+	() => ({}) as externalmakeComplexType<"defenestration">
+).types()
 
 bench(
 	"bench call and type",
-	() => {
-		return {} as makeComplexType<"antidisestablishmentarianism">
-	},
+	() => ({}) as makeComplexType<"antidisestablishmentarianism">,
 	fakeCallOptions
 )
 	.mean()
diff --git a/ark/attest/bench/bench.ts b/ark/attest/bench/bench.ts
index 28b9c131f9..b994c2d2f2 100644
--- a/ark/attest/bench/bench.ts
+++ b/ark/attest/bench/bench.ts
@@ -333,8 +333,8 @@ export const getBenchCtx = (
 	qualifiedPath: string[],
 	isAsync: boolean = false,
 	options: BenchOptions = {}
-): BenchContext => {
-	return {
+): BenchContext =>
+	({
 		qualifiedPath,
 		qualifiedName: qualifiedPath.join("/"),
 		options,
@@ -342,5 +342,4 @@ export const getBenchCtx = (
 		benchCallPosition: caller(),
 		lastSnapCallPosition: undefined,
 		isAsync
-	} as BenchContext
-}
+	}) as BenchContext
diff --git a/ark/attest/bench/measure.ts b/ark/attest/bench/measure.ts
index 33e671437e..eb3886b195 100644
--- a/ark/attest/bench/measure.ts
+++ b/ark/attest/bench/measure.ts
@@ -26,12 +26,10 @@ export type TypeUnit = (typeof TYPE_UNITS)[number]
 export const createTypeComparison = (
 	value: number,
 	baseline: Measure<TypeUnit> | undefined
-): MeasureComparison<TypeUnit> => {
-	return {
-		updated: [value, "instantiations"],
-		baseline
-	}
-}
+): MeasureComparison<TypeUnit> => ({
+	updated: [value, "instantiations"],
+	baseline
+})
 
 export const timeUnitRatios = {
 	ns: 0.000_001,
diff --git a/ark/attest/cache/getCachedAssertions.ts b/ark/attest/cache/getCachedAssertions.ts
index e8054c3cf9..dd823d64de 100644
--- a/ark/attest/cache/getCachedAssertions.ts
+++ b/ark/attest/cache/getCachedAssertions.ts
@@ -88,7 +88,7 @@ const getAssertionsOfKindAtPosition = <kind extends TypeAssertionKind>(
 					`Found no assertion data for '${fileKey}' for TypeScript version ${version}.`
 				)
 			}
-			const matchingAssertion = assertions[fileKey].find(assertion => {
+			const matchingAssertion = assertions[fileKey].find(assertion =>
 				/**
 				 * Depending on the environment, a trace can refer to any of these points
 				 * attest(...)
@@ -96,8 +96,8 @@ const getAssertionsOfKindAtPosition = <kind extends TypeAssertionKind>(
 				 * Because of this, it's safest to check if the call came from anywhere in the expected range.
 				 *
 				 */
-				return isPositionWithinRange(position, assertion.location)
-			})
+				isPositionWithinRange(position, assertion.location)
+			)
 			if (!matchingAssertion) {
 				throw new Error(
 					`Found no assertion for TypeScript version ${version} at line ${position.line} char ${position.char} in '${fileKey}'.
diff --git a/ark/attest/cache/ts.ts b/ark/attest/cache/ts.ts
index e243eaa012..2de2b8c6d0 100644
--- a/ark/attest/cache/ts.ts
+++ b/ark/attest/cache/ts.ts
@@ -20,8 +20,11 @@ export class TsServer {
 
 		const tsLibPaths = getTsLibFiles(tsConfigInfo.parsed.options)
 
+		// TS represents windows paths as `C:/Users/ssalb/...`
+		const normalizedCwd = fromCwd().replaceAll(/\\/g, "/")
+
 		this.rootFiles = tsConfigInfo.parsed.fileNames.filter(path =>
-			path.startsWith(fromCwd())
+			path.startsWith(normalizedCwd)
 		)
 
 		const system = tsvfs.createFSBackedSystem(
@@ -41,7 +44,8 @@ export class TsServer {
 	}
 
 	getSourceFileOrThrow(path: string): ts.SourceFile {
-		const file = this.virtualEnv.getSourceFile(path)
+		const tsPath = path.replaceAll(/\\/g, "/")
+		const file = this.virtualEnv.getSourceFile(tsPath)
 		if (!file) throw new Error(`Could not find ${path}.`)
 
 		return file
diff --git a/ark/attest/config.ts b/ark/attest/config.ts
index 1d0b971ade..6164d484be 100644
--- a/ark/attest/config.ts
+++ b/ark/attest/config.ts
@@ -44,25 +44,21 @@ type BaseAttestConfig = {
 
 export type AttestConfig = Partial<BaseAttestConfig>
 
-export const getDefaultAttestConfig = (): BaseAttestConfig => {
-	return {
-		tsconfig:
-			existsSync(fromCwd("tsconfig.json")) ?
-				fromCwd("tsconfig.json")
-			:	undefined,
-		attestAliases: ["attest", "attestInternal"],
-		updateSnapshots: false,
-		skipTypes: false,
-		skipInlineInstantiations: false,
-		tsVersions: "typescript",
-		benchPercentThreshold: 20,
-		benchErrorOnThresholdExceeded: false,
-		filter: undefined,
-		testDeclarationAliases: ["bench", "it"],
-		formatter: `npm exec --no -- prettier --write`,
-		shouldFormat: true
-	}
-}
+export const getDefaultAttestConfig = (): BaseAttestConfig => ({
+	tsconfig:
+		existsSync(fromCwd("tsconfig.json")) ? fromCwd("tsconfig.json") : undefined,
+	attestAliases: ["attest", "attestInternal"],
+	updateSnapshots: false,
+	skipTypes: false,
+	skipInlineInstantiations: false,
+	tsVersions: "typescript",
+	benchPercentThreshold: 20,
+	benchErrorOnThresholdExceeded: false,
+	filter: undefined,
+	testDeclarationAliases: ["bench", "it"],
+	formatter: `npm exec --no -- prettier --write`,
+	shouldFormat: true
+})
 
 const hasFlag = (flag: keyof AttestConfig) =>
 	process.argv.some(arg => arg.includes(flag))
diff --git a/ark/attest/package.json b/ark/attest/package.json
index 785a66f7f3..b99dee989d 100644
--- a/ark/attest/package.json
+++ b/ark/attest/package.json
@@ -17,7 +17,7 @@
 		"out"
 	],
 	"bin": {
-		"attest": "./out/cli/cli.js"
+		"attest": "out/cli/cli.js"
 	},
 	"scripts": {
 		"build": "tsx ../repo/build.ts",
diff --git a/ark/dark/color-theme.json b/ark/dark/color-theme.json
index 7358a6c8fc..cc46e2c3f7 100644
--- a/ark/dark/color-theme.json
+++ b/ark/dark/color-theme.json
@@ -6,49 +6,50 @@
 			"name": "functions",
 			"scope": [
 				"entity.name.function",
-				"meta.function-call",
 				"support.function",
+				"meta.function-call.python",
 				// We have this for Python in honor of contributor TizzySaurus.
 				// Will be removed for consistency once they allow it or the next time someone complains about it.
 				"meta.function.decorator punctuation",
 				"meta.function.decorator support.type"
 			],
 			"settings": {
-				"foreground": "#80cff8"
+				"foreground": "#80cff8",
+				"fontStyle": "italic"
 			}
 		},
 		{
-			"name": "types",
-			"scope": ["entity.name.type"],
+			"name": "types and decorators",
+			"scope": ["entity.name.type", "meta.decorator.ts variable"],
 			"settings": {
 				"foreground": "#40decc"
 			}
 		},
 		{
-			"name": "keywords and operators",
-			"scope": [
-				"keyword",
-				"storage",
-				"punctuation",
-				"constant.character.escape"
-			],
+			"scope": ["meta.type.declaration.ts entity.name.type"],
 			"settings": {
-				"foreground": "#eb9f2e"
+				"foreground": "#80cff8",
+				"fontStyle": "italic"
 			}
 		},
 		{
-			"name": "italics",
-			// italicize keywords that are not punctuation/symbols
-			"scope": ["keyword", "storage", "keyword.operator.expression"],
+			"scope": [
+				"meta.type.declaration.ts meta.type.parameters.ts entity.name.type"
+			],
 			"settings": {
-				"fontStyle": "italic"
+				"fontStyle": ""
 			}
 		},
 		{
-			"name": "unitalicized",
-			"scope": ["keyword.operator", "storage.type.function.arrow.ts"],
+			"name": "keywords and operators",
+			"scope": [
+				"keyword",
+				"storage",
+				"punctuation",
+				"constant.character.escape"
+			],
 			"settings": {
-				"fontStyle": ""
+				"foreground": "#ba7e41"
 			}
 		},
 		{
@@ -116,9 +117,9 @@
 		"list.errorForeground": "#9558f8",
 		"editorOverviewRuler.errorForeground": "#9558f8",
 		"editorBracketHighlight.foreground1": "#f5cf8f",
-		"editorBracketHighlight.foreground2": "#eb9f2e",
-		"editorBracketHighlight.foreground3": "#f5cf8f",
-		"editorBracketHighlight.unexpectedBracket.foreground": "#eb9f2e",
+		"editorBracketHighlight.foreground2": "#ba7e41",
+		"editorBracketHighlight.foreground3": "#eb9f2e",
+		"editorBracketHighlight.unexpectedBracket.foreground": "#ba7e41",
 		"editorCursor.foreground": "#408fde",
 		"terminalCursor.foreground": "#408fde",
 		"editorCodeLens.foreground": "#00ccff60",
diff --git a/ark/dark/injected.tmLanguage.json b/ark/dark/injected.tmLanguage.json
index 97ebb80120..3b2b7555c9 100644
--- a/ark/dark/injected.tmLanguage.json
+++ b/ark/dark/injected.tmLanguage.json
@@ -10,7 +10,7 @@
 	"repository": {
 		"arkDefinition": {
 			"contentName": "meta.embedded.arktype.definition",
-			"begin": "(([^\\)\\(\\s]*)?((\\.)?(type|scope|define|match|attest)|(\\.)(morph|and|or|when)))\\(",
+			"begin": "(([^\\)\\(\\s]*)?((\\.)?(type|scope|define|match|fn)|(\\.)(morph|and|or|when)))\\(",
 			"beginCaptures": {
 				"1": {
 					"name": "entity.name.function.ts"
diff --git a/ark/dark/package.json b/ark/dark/package.json
index 232bfc6aad..beee40f555 100644
--- a/ark/dark/package.json
+++ b/ark/dark/package.json
@@ -2,7 +2,7 @@
 	"name": "arkdark",
 	"displayName": "ArkDark",
 	"description": "ArkType syntax highlighting and themeā›µ",
-	"version": "5.0.2",
+	"version": "5.1.3",
 	"publisher": "arktypeio",
 	"type": "module",
 	"scripts": {
diff --git a/ark/dark/theme.png b/ark/dark/theme.png
new file mode 100644
index 0000000000..25ef05c7f3
Binary files /dev/null and b/ark/dark/theme.png differ
diff --git a/ark/dark/tsWithArkType.tmLanguage.json b/ark/dark/tsWithArkType.tmLanguage.json
index 6f26de8be7..42de9f493f 100644
--- a/ark/dark/tsWithArkType.tmLanguage.json
+++ b/ark/dark/tsWithArkType.tmLanguage.json
@@ -22,7 +22,7 @@
 	"repository": {
 		"arkDefinition": {
 			"contentName": "meta.embedded.arktype.definition",
-			"begin": "(([^\\)\\(\\s]*)?((\\.)?(type|scope|define|match|attest)|(\\.)(morph|and|or|when)))\\(",
+			"begin": "(([^\\)\\(\\s]*)?((\\.)?(type|scope|define|match|fn)|(\\.)(morph|and|or|when)))\\(",
 			"beginCaptures": {
 				"1": {
 					"name": "entity.name.function.ts"
diff --git a/ark/docs/package.json b/ark/docs/package.json
index 6d8e783488..daccf44540 100644
--- a/ark/docs/package.json
+++ b/ark/docs/package.json
@@ -12,22 +12,21 @@
 	},
 	"dependencies": {
 		"@arktype/util": "workspace:*",
-		"@astrojs/starlight": "0.21.1",
-		"@astrojs/react": "3.0.10",
+		"@astrojs/starlight": "0.23.0",
+		"@astrojs/react": "3.3.4",
 		"@monaco-editor/react": "4.6.0",
-		"monaco-editor": "0.47.0",
+		"monaco-editor": "0.48.0",
 		"monaco-textmate": "3.0.1",
 		"monaco-editor-textmate": "4.0.0",
 		"onigasm": "2.2.5",
-		"@stackblitz/sdk": "1.9.0",
-		"astro": "4.4.15",
-		"sharp": "0.33.2",
-		"react": "18.2.0",
-		"react-dom": "18.2.0",
-		"framer-motion": "11.0.8"
+		"astro": "4.8.6",
+		"sharp": "0.33.4",
+		"react": "18.3.1",
+		"react-dom": "18.3.1",
+		"framer-motion": "11.2.4"
 	},
 	"devDependencies": {
-		"@types/react": "18.2.64",
-		"@types/react-dom": "18.2.21"
+		"@types/react": "18.3.2",
+		"@types/react-dom": "18.3.0"
 	}
 }
diff --git a/ark/docs/src/assets/splash.png b/ark/docs/src/assets/splash.png
new file mode 100644
index 0000000000..7d9ad065f4
Binary files /dev/null and b/ark/docs/src/assets/splash.png differ
diff --git a/ark/docs/src/components/HomeDemo.tsx b/ark/docs/src/components/HomeDemo.tsx
index cc7d79e382..3086a25174 100644
--- a/ark/docs/src/components/HomeDemo.tsx
+++ b/ark/docs/src/components/HomeDemo.tsx
@@ -35,14 +35,15 @@ const translateVSCodeTheme = (
 		colors: theme.colors,
 		rules: theme.tokenColors.flatMap(c => {
 			if (Array.isArray(c.scope)) {
-				return c.scope.map(sub => {
-					return {
-						token: sub,
-						background: c.settings.background,
-						foreground: c.settings.foreground,
-						fontStyle: c.settings.fontStyle
-					} as Monaco.editor.ITokenThemeRule
-				})
+				return c.scope.map(
+					sub =>
+						({
+							token: sub,
+							background: c.settings.background,
+							foreground: c.settings.foreground,
+							fontStyle: c.settings.fontStyle
+						}) as Monaco.editor.ITokenThemeRule
+				)
 			}
 			return {
 				token: c.scope,
diff --git a/ark/docs/src/content/docs/index.mdx b/ark/docs/src/content/docs/index.mdx
index 1f8946f9d7..e58748d2d6 100644
--- a/ark/docs/src/content/docs/index.mdx
+++ b/ark/docs/src/content/docs/index.mdx
@@ -3,15 +3,19 @@ title: ArkType
 description: Documentation for ArkType, an open-source runtime validation library for TypeScript
 template: splash
 hero:
-  tagline: TypeScript's 1:1 validator, optimized from editor to runtime
+  title: ArkType
+  tagline: TypeScript's 1:1 validator, optimized from editor to runtime.
+  image:
+    alt: A serene ark, sailing to runtime
+    file: ../../assets/splash.png
   actions:
-    - text: Meet 2.0
+    - text: Set sail
       link: /intro/why/
       icon: right-arrow
       variant: primary
-    # - text: Read more
-    #   link: https://starlight.astro.build
-    #   icon: external
+    - text: Doc up
+      link: https://github.com/arktypeio/arktype
+      icon: external
 ---
 
 import { Card, CardGrid } from "@astrojs/starlight/components"
@@ -19,31 +23,25 @@ import { HeroContents } from "../../components/HeroContents.tsx"
 import { HomeDemo } from "../../components/HomeDemo.tsx"
 
 <div class="not-content">
-	<HeroContents client:only />
+	<HeroContents client:only="react" />
 </div>
 
-## v2 is coming
-
-Thank you for all the wonderful feedback on our v1 release. Basic docs for that can be found [here]().
-
-However, most of our effort has been diverted to shipping an ambitious v2 release that will establish a stable, well-documented foundation for ArkType not just as a best-in-class validator, but as the first true runtime type system for JavaScript.
-
-We coudn't be more excited to share it with you.
-
-{/* prettier-ignore */}
-{/* ## Highlights
+## What awaits
 
 <CardGrid stagger>
-	<Card title="Update content" icon="pencil">
-		Edit `src/content/docs/index.mdx` to see this page change.
+	<Card title="Unparalleled DX" icon="seti:tsconfig">
+		Type syntax you already know with safety unlike anything you've ever seen
 	</Card>
-	<Card title="Add new content" icon="add-document">
-		Add Markdown or MDX files to `src/content/docs` to create new pages.
+	<Card title="Faster. Everywhere." icon="rocket">
+		[100x faster than
+		Zod](https://moltar.github.io/typescript-runtime-type-benchmarks/) with
+		editor performance that will remind you how autocomplete is supposed to feel
 	</Card>
-	<Card title="Configure your site" icon="setting">
-		Edit your `sidebar` and other config in `astro.config.mjs`.
+	<Card title="Clear and concise" icon="magnifier">
+		Schemas are half as long and twice as readable with hovers that tell you
+		just what really matters
 	</Card>
-	<Card title="Read the docs" icon="open-book">
-		Learn more in [the Starlight Docs](https://starlight.astro.build/).
+	<Card title="Better errors" icon="error">
+		Deeply customizable and composable messages with great defaults
 	</Card>
-</CardGrid> */}
+</CardGrid>
diff --git a/ark/docs/src/content/docs/intro/why.md b/ark/docs/src/content/docs/intro/why.md
index dc58a21d5a..a720fcdeb4 100644
--- a/ark/docs/src/content/docs/intro/why.md
+++ b/ark/docs/src/content/docs/intro/why.md
@@ -5,13 +5,8 @@ description: A guide in my new Starlight docs site.
 
 ## Why use it?
 
-- **Performance**:
-  - In editor: Types are 3x more efficient than Zod
-  - At runtime: 400x faster than Zod, 2000x faster than Yup
 - **Concision**:
   - Definitions: About 1/2 as long as equivalent Zod on average
   - Types: Tooltips are 1/5 the length of Zod on average
 - **Portability**:
   - Definitions are just strings and objects and are serializable by default.
-- **Developer Experience**:
-  - With semantic validation and contextual autocomplete, ArkType's static parser is unlike anything you've ever seen.
diff --git a/ark/fs/getCurrentLine.ts b/ark/fs/getCurrentLine.ts
index 1009e3b1ab..4ce377279b 100644
--- a/ark/fs/getCurrentLine.ts
+++ b/ark/fs/getCurrentLine.ts
@@ -227,6 +227,4 @@ export const getCurrentLine = (
 		frames: 0,
 		immediate: false
 	}
-): Location => {
-	return getLocationFromError(new Error(), offset)
-}
+): Location => getLocationFromError(new Error(), offset)
diff --git a/ark/repo/.eslintrc.cjs b/ark/repo/.eslintrc.cjs
index cc5161e2fa..9f1b9711ab 100644
--- a/ark/repo/.eslintrc.cjs
+++ b/ark/repo/.eslintrc.cjs
@@ -51,6 +51,7 @@ module.exports = defineConfig({
 				disallowPrototype: true
 			}
 		],
+		"arrow-body-style": ["warn", "as-needed"],
 		"@typescript-eslint/no-unused-vars": [
 			"warn",
 			{
@@ -59,10 +60,6 @@ module.exports = defineConfig({
 				ignoreRestSiblings: true
 			}
 		],
-		"@typescript-eslint/explicit-module-boundary-types": [
-			"warn",
-			{ allowDirectConstAssertionInArrowFunctions: true }
-		],
 		"@typescript-eslint/default-param-last": "warn",
 		"@typescript-eslint/no-empty-interface": "off",
 		/**
diff --git a/ark/repo/arkConfig.ts b/ark/repo/arkConfig.ts
index 0ba82e660b..8396ee19d4 100644
--- a/ark/repo/arkConfig.ts
+++ b/ark/repo/arkConfig.ts
@@ -1,10 +1,5 @@
-// import { configure } from "arktype/config"
-// // import { type } from "arktype"
+import { configure } from "arktype/config"
 
-// // const user = type("string")
-
-// configure({
-// 	domain: {
-// 		description: (inner) => `my special ${inner.domain}`
-// 	}
-// })
+configure({
+	jitless: true
+})
diff --git a/ark/repo/build.ts b/ark/repo/build.ts
index ef25fd305d..44f00486f4 100644
--- a/ark/repo/build.ts
+++ b/ark/repo/build.ts
@@ -1,8 +1,11 @@
+import { fromCwd, rmRf, shell, writeJson } from "@arktype/fs"
 import { symlinkSync, unlinkSync } from "fs"
-// eslint-disable-next-line @typescript-eslint/no-restricted-imports
-import { fromCwd, shell, writeJson } from "../fs/api.js"
+import { join } from "path"
 
 const isCjs = process.argv.includes("--cjs") || process.env.ARKTYPE_CJS
+const outDir = fromCwd("out")
+
+rmRf(outDir)
 
 try {
 	if (isCjs) {
@@ -10,7 +13,7 @@ try {
 		symlinkSync(`../repo/tsconfig.cjs.json`, "tsconfig.build.json")
 	}
 	shell("pnpm tsc --project tsconfig.build.json")
-	if (isCjs) writeJson(fromCwd("out", "package.json"), { type: "commonjs" })
+	if (isCjs) writeJson(join(outDir, "package.json"), { type: "commonjs" })
 } finally {
 	if (isCjs) {
 		unlinkSync("tsconfig.build.json")
diff --git a/ark/repo/scratch.ts b/ark/repo/scratch.ts
index d01f668c4e..c050722a2d 100644
--- a/ark/repo/scratch.ts
+++ b/ark/repo/scratch.ts
@@ -1,23 +1,34 @@
 import { type } from "arktype"
 
-// type Z = Type<{ age: number.default<5> }>
+const parseBigint = type("string", "=>", (s, ctx) => {
+	try {
+		return BigInt(s)
+	} catch {
+		return ctx.error("a valid number")
+	}
+})
 
-const f = (arg?: string) => {}
+// or
 
-const user = type({
-	"+": "delete",
-	name: "string>10",
-	email: "email"
-	// age: ["number", "=", 5]
+const parseBigint2 = type("string").pipe((s, ctx) => {
+	try {
+		return BigInt(s)
+	} catch {
+		return ctx.error("a valid number")
+	}
 })
 
-const out = user({
-	name: "test",
-	email: ""
+const Test = type({
+	group: {
+		nested: {
+			value: parseBigint
+		}
+	}
 })
 
-if (out instanceof type.errors) {
-	console.log(out.summary)
-} else {
-	console.log(out)
+const myFunc = () => {
+	const out = Test({})
+	if (out instanceof type.errors) return
+
+	const value: bigint = out.group.nested.value
 }
diff --git a/ark/schema/__tests__/parse.bench.ts b/ark/schema/__tests__/parse.bench.ts
index 5f32a1932b..593f138a42 100644
--- a/ark/schema/__tests__/parse.bench.ts
+++ b/ark/schema/__tests__/parse.bench.ts
@@ -1,13 +1,12 @@
 import { bench } from "@arktype/attest"
 import { schema } from "@arktype/schema"
 
-bench("domain", () => {
-	return schema("string").infer
-}).types([2, "instantiations"])
+bench("domain", () => schema("string").infer).types([2, "instantiations"])
 
-bench("intersection", () => {
-	return schema("string").and(schema("number"))
-}).types([846, "instantiations"])
+bench("intersection", () => schema("string").and(schema("number"))).types([
+	846,
+	"instantiations"
+])
 
 bench("no assignment", () => {
 	schema({ domain: "string", regex: "/.*/" })
diff --git a/ark/schema/api.ts b/ark/schema/api.ts
index 5c20e0a7d9..4298fc1a27 100644
--- a/ark/schema/api.ts
+++ b/ark/schema/api.ts
@@ -23,7 +23,6 @@ export * from "./refinements/min.js"
 export * from "./refinements/minLength.js"
 export * from "./refinements/range.js"
 export * from "./refinements/regex.js"
-export * from "./roots/discriminate.js"
 export * from "./roots/intersection.js"
 export * from "./roots/morph.js"
 export * from "./roots/root.js"
diff --git a/ark/schema/constraint.ts b/ark/schema/constraint.ts
index ba74af180d..f221cf2329 100644
--- a/ark/schema/constraint.ts
+++ b/ark/schema/constraint.ts
@@ -79,7 +79,12 @@ export abstract class RawPrimitiveConstraint<
 	}
 
 	compile(js: NodeCompiler): void {
-		js.compilePrimitive(this as never)
+		if (js.traversalKind === "Allows") js.return(this.compiledCondition)
+		else {
+			js.if(this.compiledNegation, () =>
+				js.line(`${js.ctx}.error(${this.compiledErrorContext})`)
+			)
+		}
 	}
 
 	get errorContext(): d["errorContext"] {
diff --git a/ark/schema/inference.ts b/ark/schema/inference.ts
index 3a3627da05..f0e9eed1d5 100644
--- a/ark/schema/inference.ts
+++ b/ark/schema/inference.ts
@@ -68,8 +68,7 @@ type inferRootBranch<schema, $> =
 	: schema extends MorphSchema ?
 		(
 			In: schema["in"] extends {} ? inferMorphChild<schema["in"], $> : unknown
-		) => schema["out"] extends {} ? Out<inferMorphChild<schema["out"], $>>
-		: schema["morphs"] extends infer morph extends Morph ?
+		) => schema["morphs"] extends infer morph extends Morph ?
 			Out<inferMorphOut<morph>>
 		: schema["morphs"] extends (
 			readonly [...unknown[], infer morph extends Morph]
diff --git a/ark/schema/keywords/internal.ts b/ark/schema/keywords/internal.ts
index 32974c4715..17bfb46d56 100644
--- a/ark/schema/keywords/internal.ts
+++ b/ark/schema/keywords/internal.ts
@@ -1,10 +1,14 @@
 import type { Key } from "@arktype/util"
 import type { SchemaModule } from "../module.js"
 import { root, schemaScope } from "../scope.js"
+// these are needed to create some internal types
+import { arrayIndexMatcher } from "../structure/shared.js"
+import "./tsKeywords.js"
 
 export interface internalKeywordExports {
 	lengthBoundable: string | unknown[]
 	propertyKey: Key
+	nonNegativeIntegerString: string
 }
 
 export type internalKeywords = SchemaModule<internalKeywordExports>
@@ -12,7 +16,8 @@ export type internalKeywords = SchemaModule<internalKeywordExports>
 export const internalKeywords: internalKeywords = schemaScope(
 	{
 		lengthBoundable: ["string", Array],
-		propertyKey: ["string", "symbol"]
+		propertyKey: ["string", "symbol"],
+		nonNegativeIntegerString: { domain: "string", regex: arrayIndexMatcher }
 	},
 	{
 		prereducedAliases: true,
diff --git a/ark/schema/keywords/parsing.ts b/ark/schema/keywords/parsing.ts
index 1c35849416..24545298c5 100644
--- a/ark/schema/keywords/parsing.ts
+++ b/ark/schema/keywords/parsing.ts
@@ -7,21 +7,15 @@ import type { SchemaModule } from "../module.js"
 import type { Out } from "../roots/morph.js"
 import { root, schemaScope } from "../scope.js"
 import { tryParseDatePattern } from "./utils/date.js"
+import { defineRegex } from "./utils/regex.js"
 
 const number = root.defineRoot({
-	in: {
-		domain: "string",
-		regex: wellFormedNumberMatcher,
-		description: "a well-formed numeric string"
-	},
+	in: defineRegex(wellFormedNumberMatcher, "a well-formed numeric string"),
 	morphs: (s: string) => Number.parseFloat(s)
 })
 
 const integer = root.defineRoot({
-	in: {
-		domain: "string",
-		regex: wellFormedIntegerMatcher
-	},
+	in: defineRegex(wellFormedIntegerMatcher, "a well-formed integer string"),
 	morphs: (s: string, ctx) => {
 		if (!isWellFormedInteger(s))
 			return ctx.error("a well-formed integer string")
@@ -36,10 +30,7 @@ const integer = root.defineRoot({
 })
 
 const url = root.defineRoot({
-	in: {
-		domain: "string",
-		description: "a valid URL"
-	},
+	in: "string",
 	morphs: (s: string, ctx) => {
 		try {
 			return new URL(s)
@@ -50,11 +41,14 @@ const url = root.defineRoot({
 })
 
 const json = root.defineRoot({
-	in: {
-		domain: "string",
-		description: "a JSON-parsable string"
-	},
-	morphs: (s: string): unknown => JSON.parse(s)
+	in: "string",
+	morphs: (s: string, ctx): object => {
+		try {
+			return JSON.parse(s)
+		} catch {
+			return ctx.error("a valid JSON string")
+		}
+	}
 })
 
 const date = root.defineRoot({
@@ -70,7 +64,7 @@ export type parsingExports = {
 	number: (In: string) => Out<number>
 	integer: (In: string) => Out<number>
 	date: (In: string) => Out<Date>
-	json: (In: string) => Out<unknown>
+	json: (In: string) => Out<object>
 }
 
 export type parsing = SchemaModule<parsingExports>
diff --git a/ark/schema/keywords/utils/ip.ts b/ark/schema/keywords/utils/ip.ts
new file mode 100644
index 0000000000..5b1640fbeb
--- /dev/null
+++ b/ark/schema/keywords/utils/ip.ts
@@ -0,0 +1,27 @@
+import { root } from "../../scope.js"
+import { defineRegex } from "./regex.js"
+
+// Based on https://github.com/validatorjs/validator.js/blob/master/src/lib/isIP.js
+const ipv4Segment = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
+const ipv4Address = `(${ipv4Segment}[.]){3}${ipv4Segment}`
+const ipv4Matcher = new RegExp(`^${ipv4Address}$`)
+
+export const ipv4 = defineRegex(ipv4Matcher, "a valid IPv4 address")
+
+const ipv6Segment = "(?:[0-9a-fA-F]{1,4})"
+const ipv6Matcher = new RegExp(
+	"^(" +
+		`(?:${ipv6Segment}:){7}(?:${ipv6Segment}|:)|` +
+		`(?:${ipv6Segment}:){6}(?:${ipv4Address}|:${ipv6Segment}|:)|` +
+		`(?:${ipv6Segment}:){5}(?::${ipv4Address}|(:${ipv6Segment}){1,2}|:)|` +
+		`(?:${ipv6Segment}:){4}(?:(:${ipv6Segment}){0,1}:${ipv4Address}|(:${ipv6Segment}){1,3}|:)|` +
+		`(?:${ipv6Segment}:){3}(?:(:${ipv6Segment}){0,2}:${ipv4Address}|(:${ipv6Segment}){1,4}|:)|` +
+		`(?:${ipv6Segment}:){2}(?:(:${ipv6Segment}){0,3}:${ipv4Address}|(:${ipv6Segment}){1,5}|:)|` +
+		`(?:${ipv6Segment}:){1}(?:(:${ipv6Segment}){0,4}:${ipv4Address}|(:${ipv6Segment}){1,6}|:)|` +
+		`(?::((?::${ipv6Segment}){0,5}:${ipv4Address}|(?::${ipv6Segment}){1,7}|:))` +
+		")(%[0-9a-zA-Z-.:]{1,})?$"
+)
+
+export const ipv6 = defineRegex(ipv6Matcher, "a valid IPv6 address")
+
+export const ip = root.defineRoot([ipv4, ipv6])
diff --git a/ark/schema/keywords/utils/regex.ts b/ark/schema/keywords/utils/regex.ts
new file mode 100644
index 0000000000..6e06d2991d
--- /dev/null
+++ b/ark/schema/keywords/utils/regex.ts
@@ -0,0 +1,15 @@
+import type { NormalizedRegexSchema } from "../../refinements/regex.js"
+import { root } from "../../scope.js"
+
+export const defineRegex = (
+	regex: RegExp,
+	description: string
+): { domain: "string"; regex: NormalizedRegexSchema } =>
+	root.defineRoot({
+		domain: "string",
+		regex: {
+			rule: regex.source,
+			flags: regex.flags,
+			description
+		}
+	})
diff --git a/ark/schema/keywords/validation.ts b/ark/schema/keywords/validation.ts
index 5cc65d3943..555683b200 100644
--- a/ark/schema/keywords/validation.ts
+++ b/ark/schema/keywords/validation.ts
@@ -1,6 +1,8 @@
 import type { SchemaModule } from "../module.js"
 import { root, schemaScope } from "../scope.js"
 import { creditCardMatcher, isLuhnValid } from "./utils/creditCard.js"
+import { ip } from "./utils/ip.js"
+import { defineRegex } from "./utils/regex.js"
 
 // Non-trivial expressions should have an explanation or attribution
 
@@ -22,37 +24,22 @@ const url = root.defineRoot({
 // https://www.regular-expressions.info/email.html
 const emailMatcher = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/
 
-const email = root.defineRoot({
-	domain: "string",
-	regex: {
-		rule: emailMatcher.source,
-		description: "a valid email"
-	}
-})
+const email = defineRegex(emailMatcher, "a valid email")
 
 const uuidMatcher =
 	/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/
 
 // https://github.com/validatorjs/validator.js/blob/master/src/lib/isUUID.js
-const uuid = root.defineRoot({
-	domain: "string",
-	regex: {
-		rule: uuidMatcher.source,
-		description: "a valid UUID"
-	}
-})
+const uuid = defineRegex(uuidMatcher, "a valid UUID")
 
 const semverMatcher =
 	/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
 
 // https://semver.org/
-const semver = root.defineRoot({
-	domain: "string",
-	regex: {
-		rule: semverMatcher.source,
-		description: "a valid semantic version (see https://semver.org/)"
-	}
-})
+const semver = defineRegex(
+	semverMatcher,
+	"a valid semantic version (see https://semver.org/)"
+)
 
 const creditCard = root.defineRoot({
 	domain: "string",
@@ -76,6 +63,7 @@ export interface validationExports {
 	uuid: string
 	url: string
 	semver: string
+	ip: string
 	integer: number
 }
 
@@ -83,37 +71,16 @@ export type validation = SchemaModule<validationExports>
 
 export const validation: validation = schemaScope(
 	{
-		alpha: {
-			domain: "string",
-			regex: /^[A-Za-z]*$/,
-			description: "only letters"
-		},
-		alphanumeric: {
-			domain: "string",
-			regex: {
-				rule: /^[A-Za-z\d]*$/.source,
-				description: "only letters and digits"
-			}
-		},
-		lowercase: {
-			domain: "string",
-			regex: {
-				rule: /^[a-z]*$/.source,
-				description: "only lowercase letters"
-			}
-		},
-		uppercase: {
-			domain: "string",
-			regex: {
-				rule: /^[A-Za-z]*$/.source,
-				description: "only uppercase letters"
-			}
-		},
+		alpha: defineRegex(/^[A-Za-z]*$/, "only letters"),
+		alphanumeric: defineRegex(/^[A-Za-z\d]*$/, "only letters and digits"),
+		lowercase: defineRegex(/^[a-z]*$/, "only lowercase letters"),
+		uppercase: defineRegex(/^[A-Z]*$/, "only uppercase letters"),
 		creditCard,
 		email,
 		uuid,
 		url,
 		semver,
+		ip,
 		integer: {
 			domain: "number",
 			divisor: 1
diff --git a/ark/schema/node.ts b/ark/schema/node.ts
index 335d222ac4..b2d95295c0 100644
--- a/ark/schema/node.ts
+++ b/ark/schema/node.ts
@@ -3,16 +3,18 @@ import {
 	flatMorph,
 	includes,
 	isArray,
+	isEmptyObject,
 	shallowClone,
 	throwError,
 	type Dict,
 	type Guardable,
 	type Json,
+	type Key,
 	type conform,
 	type listable
 } from "@arktype/util"
 import type { BaseConstraint } from "./constraint.js"
-import type { Inner, Node, reducibleKindOf } from "./kinds.js"
+import type { Inner, MutableInner, Node, reducibleKindOf } from "./kinds.js"
 import type { BaseRoot, Root } from "./roots/root.js"
 import type { UnitNode } from "./roots/unit.js"
 import type { RawRootScope } from "./scope.js"
@@ -49,7 +51,9 @@ export abstract class BaseNode<
 > extends Callable<(data: d["prerequisite"]) => unknown, attachmentsOf<d>> {
 	constructor(public attachments: UnknownAttachments) {
 		super(
-			(data: any) => {
+			// pipedFromCtx allows us internally to reuse TraversalContext
+			// through pipes and keep track of piped paths. It is not exposed
+			(data: any, pipedFromCtx?: TraversalContext) => {
 				if (
 					!this.includesMorph &&
 					!this.allowsRequiresContext &&
@@ -57,17 +61,14 @@ export abstract class BaseNode<
 				)
 					return data
 
+				if (pipedFromCtx) return this.traverseApply(data, pipedFromCtx)
+
 				const ctx = new TraversalContext(data, this.$.resolvedConfig)
 				this.traverseApply(data, ctx)
 				return ctx.finalize()
 			},
 			{ attach: attachments as never }
 		)
-		this.contributesReferencesById =
-			this.id in this.referencesByName ?
-				this.referencesByName
-			:	{ ...this.referencesByName, [this.id]: this as never }
-		this.contributesReferences = Object.values(this.contributesReferencesById)
 	}
 
 	abstract traverseAllows: TraverseAllows<d["prerequisite"]>
@@ -86,15 +87,15 @@ export abstract class BaseNode<
 		(this.hasKind("predicate") && this.inner.predicate.length !== 1) ||
 		this.kind === "alias" ||
 		this.children.some(child => child.allowsRequiresContext)
-	readonly referencesByName: Record<string, BaseNode> = this.children.reduce(
-		(result, child) => Object.assign(result, child.contributesReferencesById),
-		{}
-	)
-	readonly references: readonly BaseNode[] = Object.values(
-		this.referencesByName
+	readonly referencesById: Record<string, BaseNode> = this.children.reduce(
+		(result, child) => Object.assign(result, child.referencesById),
+		{ [this.id]: this }
 	)
-	readonly contributesReferencesById: Record<string, BaseNode>
-	readonly contributesReferences: readonly BaseNode[]
+
+	get references(): BaseNode[] {
+		return Object.values(this.referencesById)
+	}
+
 	readonly precedence: number = precedenceOfKind(this.kind)
 	jit = false
 
@@ -140,10 +141,10 @@ export abstract class BaseNode<
 
 		const ioInner: Record<any, unknown> = {}
 		for (const [k, v] of this.entries) {
-			const keySchemainition = this.impl.keys[k]
-			if (keySchemainition.meta) continue
+			const keySchemaImplementation = this.impl.keys[k]
+			if (keySchemaImplementation.meta) continue
 
-			if (keySchemainition.child) {
+			if (keySchemaImplementation.child) {
 				const childValue = v as listable<BaseNode>
 				ioInner[k] =
 					isArray(childValue) ?
@@ -209,7 +210,7 @@ export abstract class BaseNode<
 	firstReference<narrowed>(
 		filter: Guardable<BaseNode, conform<narrowed, BaseNode>>
 	): narrowed | undefined {
-		return this.references.find(filter as never) as never
+		return this.references.find(n => n !== this && filter(n)) as never
 	}
 
 	firstReferenceOrThrow<narrowed extends BaseNode>(
@@ -234,49 +235,74 @@ export abstract class BaseNode<
 		)
 	}
 
-	transform(
-		mapper: DeepNodeTransformation,
-		shouldTransform: ShouldTransformFn
-	): Node<reducibleKindOf<this["kind"]>> {
-		return this._transform(mapper, shouldTransform, { seen: {} }) as never
+	transform<mapper extends DeepNodeTransformation>(
+		mapper: mapper,
+		opts?: DeepNodeTransformOptions
+	): Node<reducibleKindOf<this["kind"]>> | Extract<ReturnType<mapper>, null> {
+		return this._transform(mapper, {
+			seen: {},
+			path: [],
+			shouldTransform: opts?.shouldTransform ?? (() => true)
+		}) as never
 	}
 
-	private _transform(
+	protected _transform(
 		mapper: DeepNodeTransformation,
-		shouldTransform: ShouldTransformFn,
 		ctx: DeepNodeTransformationContext
-	): BaseNode {
+	): BaseNode | null {
 		if (ctx.seen[this.id])
 			// TODO: remove cast by making lazilyResolve more flexible
 			// TODO: if each transform has a unique base id, could ensure
 			// these don't create duplicates
 			return this.$.lazilyResolve(ctx.seen[this.id]! as never)
-		if (!shouldTransform(this as never, ctx)) return this
+		if (!ctx.shouldTransform(this as never, ctx)) return this
+
+		let transformedNode: BaseRoot | undefined
 
-		ctx.seen[this.id] = () => node
+		ctx.seen[this.id] = () => transformedNode
 
 		const innerWithTransformedChildren = flatMorph(
 			this.inner as Dict,
-			(k, v) => [
-				k,
-				this.impl.keys[k].child ?
-					isArray(v) ?
-						v.map(node =>
-							(node as BaseNode)._transform(mapper, shouldTransform, ctx)
-						)
-					:	(v as BaseNode)._transform(mapper, shouldTransform, ctx)
-				:	v
-			]
+			(k, v) => {
+				if (!this.impl.keys[k].child) return [k, v]
+				const children = v as listable<BaseNode>
+				if (!isArray(children)) {
+					const transformed = children._transform(mapper, ctx)
+					return transformed ? [k, transformed] : []
+				}
+				const transformed = children.flatMap(n => {
+					const transformedChild = n._transform(mapper, ctx)
+					return transformedChild ?? []
+				})
+				return transformed.length ? [k, transformed] : []
+			}
 		)
 
 		delete ctx.seen[this.id]
 
-		const node = this.$.node(
+		const transformedInner = mapper(
 			this.kind,
-			mapper(this.kind, innerWithTransformedChildren as never, ctx) as never
+			innerWithTransformedChildren as never,
+			ctx
 		)
 
-		return node
+		if (transformedInner === null) return null
+		// TODO: more robust checks for pruned inner
+		if (isEmptyObject(transformedInner)) return null
+
+		if (
+			(this.kind === "required" ||
+				this.kind === "optional" ||
+				this.kind === "index") &&
+			!("value" in transformedInner)
+		)
+			return null
+		if (this.kind === "morph") {
+			;(transformedInner as MutableInner<"morph">).in ??= this.$.keywords
+				.unknown as never
+		}
+
+		return (transformedNode = this.$.node(this.kind, transformedInner) as never)
 	}
 
 	configureShallowDescendants(configOrDescription: BaseMeta | string): this {
@@ -284,24 +310,30 @@ export abstract class BaseNode<
 			typeof configOrDescription === "string" ?
 				{ description: configOrDescription }
 			:	(configOrDescription as never)
-		return this.transform(
-			(kind, inner) => ({ ...inner, ...config }),
-			node => node.kind !== "structure"
-		) as never
+		return this.transform((kind, inner) => ({ ...inner, ...config }), {
+			shouldTransform: node => node.kind !== "structure"
+		}) as never
 	}
 }
 
+export type DeepNodeTransformOptions = {
+	shouldTransform: ShouldTransformFn
+}
+
 export type ShouldTransformFn = (
 	node: BaseNode,
 	ctx: DeepNodeTransformationContext
 ) => boolean
 
 export type DeepNodeTransformationContext = {
-	seen: { [originalId: string]: (() => BaseNode) | undefined }
+	/** a literal key or a node representing the key of an index signature */
+	path: Array<Key | BaseNode>
+	seen: { [originalId: string]: (() => BaseNode | undefined) | undefined }
+	shouldTransform: ShouldTransformFn
 }
 
 export type DeepNodeTransformation = <kind extends NodeKind>(
 	kind: kind,
 	inner: Inner<kind>,
 	ctx: DeepNodeTransformationContext
-) => Inner<kind>
+) => Inner<kind> | null
diff --git a/ark/schema/refinements/exactLength.ts b/ark/schema/refinements/exactLength.ts
index 1ecfb53af9..628330203a 100644
--- a/ark/schema/refinements/exactLength.ts
+++ b/ark/schema/refinements/exactLength.ts
@@ -42,7 +42,7 @@ export const exactLengthImplementation: nodeImplementationOf<ExactLengthDeclarat
 		intersections: {
 			exactLength: (l, r, ctx) =>
 				new Disjoint({
-					"[length]": {
+					'["length"]': {
 						unit: {
 							l: ctx.$.node("unit", { unit: l.rule }),
 							r: ctx.$.node("unit", { unit: r.rule })
diff --git a/ark/schema/roots/basis.ts b/ark/schema/roots/basis.ts
index 6c811d9db2..40b86dfc4e 100644
--- a/ark/schema/roots/basis.ts
+++ b/ark/schema/roots/basis.ts
@@ -29,6 +29,11 @@ export abstract class RawBasis<
 	}
 
 	compile(js: NodeCompiler): void {
-		js.compilePrimitive(this as never)
+		if (js.traversalKind === "Allows") js.return(this.compiledCondition)
+		else {
+			js.if(this.compiledNegation, () =>
+				js.line(`${js.ctx}.error(${this.compiledErrorContext})`)
+			)
+		}
 	}
 }
diff --git a/ark/schema/roots/discriminate.ts b/ark/schema/roots/discriminate.ts
deleted file mode 100644
index 95af5416c0..0000000000
--- a/ark/schema/roots/discriminate.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-import {
-	type Domain,
-	type SerializedPrimitive,
-	compileSerializedValue,
-	entriesOf,
-	isKeyOf,
-	type keySet,
-	type mutable,
-	type show,
-	throwInternalError
-} from "@arktype/util"
-import { Disjoint, type SerializedPath } from "../shared/disjoint.js"
-import { intersectNodesRoot } from "../shared/intersections.js"
-import type { UnionChildNode } from "./union.js"
-
-export type CaseKey<kind extends DiscriminantKind = DiscriminantKind> =
-	DiscriminantKind extends kind ? string : DiscriminantKinds[kind] | "default"
-
-export type Discriminant<kind extends DiscriminantKind = DiscriminantKind> =
-	Readonly<{
-		readonly path: string[]
-		readonly kind: kind
-		readonly cases: DiscriminatedCases<kind>
-		// TODO: add default here?
-		readonly isPureRootLiteral: boolean
-	}>
-
-export type DiscriminatedCases<
-	kind extends DiscriminantKind = DiscriminantKind
-> = Readonly<{
-	[caseKey in CaseKey<kind>]: Discriminant | UnionChildNode[]
-}>
-
-type DiscriminantKey = `${SerializedPath}${DiscriminantKind}`
-
-type CasesBySpecifier = {
-	[k in DiscriminantKey]?: Record<string, UnionChildNode[]>
-}
-
-export type DiscriminantKinds = {
-	domain: Domain
-	value: SerializedPrimitive
-}
-
-const discriminantKinds: keySet<DiscriminantKind> = {
-	domain: 1,
-	value: 1
-}
-
-export type DiscriminantKind = show<keyof DiscriminantKinds>
-
-const parseDiscriminantKey = (key: DiscriminantKey) => {
-	const lastPathIndex = key.lastIndexOf("]")
-	return [
-		JSON.parse(key.slice(0, lastPathIndex + 1)),
-		key.slice(lastPathIndex + 1)
-	] as [path: string[], kind: DiscriminantKind]
-}
-
-const discriminantCache = new Map<
-	readonly UnionChildNode[],
-	Discriminant | null
->()
-
-export const discriminate = (
-	branches: readonly UnionChildNode[]
-): Discriminant | null => {
-	if (branches.length < 2) return null
-
-	const cached = discriminantCache.get(branches)
-	if (cached !== undefined) return cached
-
-	// const pureValueBranches = branches.flatMap((branch) =>
-	// 	branch.unit ? branch.unit : []
-	// )
-	// if (pureValueBranches.length === branches.length) {
-	// 	const cases: DiscriminatedCases = transform(
-	// 		pureValueBranches,
-	// 		([i, valueNode]) => [valueNode.serialized, [branches[i]]]
-	// 	)
-	// 	return {
-	// 		path: [],
-	// 		kind: "value",
-	// 		cases,
-	// 		isPureRootLiteral: true
-	// 	}
-	// }
-	const casesBySpecifier: CasesBySpecifier = {}
-	for (let lIndex = 0; lIndex < branches.length - 1; lIndex++) {
-		const l = branches[lIndex]
-		for (let rIndex = lIndex + 1; rIndex < branches.length; rIndex++) {
-			const r = branches[rIndex]
-			const result = intersectNodesRoot(l, r, l.$)
-			if (!(result instanceof Disjoint)) continue
-
-			for (const { path, kind, disjoint } of result.flat) {
-				if (!isKeyOf(kind, discriminantKinds)) continue
-
-				const qualifiedDiscriminant: DiscriminantKey = `${path}${kind}`
-				let lSerialized: string
-				let rSerialized: string
-				if (kind === "domain") {
-					lSerialized = disjoint.l as Domain
-					rSerialized = disjoint.r as Domain
-				} else if (kind === "value") {
-					lSerialized = compileSerializedValue(disjoint.l)
-					rSerialized = compileSerializedValue(disjoint.r)
-				} else {
-					return throwInternalError(
-						`Unexpected attempt to discriminate disjoint kind '${kind}'`
-					)
-				}
-				if (!casesBySpecifier[qualifiedDiscriminant]) {
-					casesBySpecifier[qualifiedDiscriminant] = {
-						[lSerialized]: [l],
-						[rSerialized]: [r]
-					}
-					continue
-				}
-				const cases = casesBySpecifier[qualifiedDiscriminant]!
-				if (!isKeyOf(lSerialized, cases)) cases[lSerialized] = [l]
-				else if (!cases[lSerialized].includes(l)) cases[lSerialized].push(l)
-
-				if (!isKeyOf(rSerialized, cases)) cases[rSerialized] = [r]
-				else if (!cases[rSerialized].includes(r)) cases[rSerialized].push(r)
-			}
-		}
-	}
-	// TODO: determinstic? Update cache key?
-	const bestDiscriminantEntry = entriesOf(casesBySpecifier)
-		.sort((a, b) => Object.keys(a[1]).length - Object.keys(b[1]).length)
-		.at(-1)
-	if (!bestDiscriminantEntry) {
-		discriminantCache.set(branches, null)
-		return null
-	}
-	const [specifier, predicateCases] = bestDiscriminantEntry
-	const [path, kind] = parseDiscriminantKey(specifier)
-	const cases: mutable<DiscriminatedCases> = {}
-	for (const k in predicateCases) {
-		const subdiscriminant = discriminate(predicateCases[k])
-		cases[k] = subdiscriminant ?? predicateCases[k]
-	}
-	const discriminant: Discriminant = {
-		kind,
-		path,
-		cases,
-		isPureRootLiteral: false
-	}
-	discriminantCache.set(branches, discriminant)
-	return discriminant
-}
-
-// // TODO: if deeply includes morphs?
-// const writeUndiscriminableMorphUnionMessage = <path extends string>(
-// 	path: path
-// ) =>
-// 	`${
-// 		path === "/" ? "A" : `At ${path}, a`
-// 	} union including one or more morphs must be discriminable` as const
diff --git a/ark/schema/roots/intersection.ts b/ark/schema/roots/intersection.ts
index b1ffa10df5..a3f3b0d4ce 100644
--- a/ark/schema/roots/intersection.ts
+++ b/ark/schema/roots/intersection.ts
@@ -332,9 +332,7 @@ export const intersectionImplementation: nodeImplementationOf<IntersectionDeclar
 			problem: ctx => `must be...\n${ctx.expected}`
 		},
 		intersections: {
-			intersection: (l, r, ctx) => {
-				return intersectIntersections(l, r, ctx)
-			},
+			intersection: (l, r, ctx) => intersectIntersections(l, r, ctx),
 			...defineRightwardIntersections("intersection", (l, r, ctx) => {
 				// if l is unknown, return r
 				if (l.children.length === 0) return r
diff --git a/ark/schema/roots/morph.ts b/ark/schema/roots/morph.ts
index bfdde87d9d..24a2358a3e 100644
--- a/ark/schema/roots/morph.ts
+++ b/ark/schema/roots/morph.ts
@@ -12,7 +12,7 @@ import {
 } from "@arktype/util"
 import type { of } from "../ast.js"
 import type { type } from "../inference.js"
-import type { Node, NodeSchema, RootSchema } from "../kinds.js"
+import type { Node, NodeSchema } from "../kinds.js"
 import type { StaticArkOption } from "../scope.js"
 import type { NodeCompiler } from "../shared/compile.js"
 import type { BaseMeta, declareNode } from "../shared/declare.js"
@@ -28,8 +28,9 @@ import type {
 	TraverseAllows,
 	TraverseApply
 } from "../shared/traversal.js"
+import { hasArkKind } from "../shared/utils.js"
 import type { DefaultableAst } from "../structure/optional.js"
-import { BaseRoot, type schemaKindRightOf } from "./root.js"
+import { BaseRoot, type Root, type schemaKindRightOf } from "./root.js"
 import { defineRightwardIntersections } from "./utils.js"
 
 export type MorphInputKind = schemaKindRightOf<"morph">
@@ -53,14 +54,12 @@ export type MorphAst<i = any, o = any> = (In: i) => Out<o>
 
 export interface MorphInner extends BaseMeta {
 	readonly in: MorphInputNode
-	readonly out?: BaseRoot
-	readonly morphs: readonly Morph[]
+	readonly morphs: array<Morph | Root>
 }
 
 export interface MorphSchema extends BaseMeta {
 	readonly in: MorphInputSchema
-	readonly out?: RootSchema | undefined
-	readonly morphs: listable<Morph>
+	readonly morphs: listable<Morph | Root>
 }
 
 export interface MorphDeclaration
@@ -81,20 +80,12 @@ export const morphImplementation: nodeImplementationOf<MorphDeclaration> =
 				child: true,
 				parse: (schema, ctx) => ctx.$.node(morphInputKinds, schema)
 			},
-			out: {
-				child: true,
-				parse: (schema, ctx) => {
-					if (schema === undefined) return
-					const out = ctx.$.schema(schema)
-					return out.kind === "intersection" && out.children.length === 0 ?
-							// ignore unknown as an output validator
-							undefined
-						:	out
-				}
-			},
 			morphs: {
 				parse: arrayFrom,
-				serialize: morphs => morphs.map(registeredReference)
+				serialize: morphs =>
+					morphs.map(m =>
+						hasArkKind(m, "root") ? m.json : registeredReference(m)
+					)
 			}
 		},
 		normalize: schema => schema,
@@ -109,21 +100,14 @@ export const morphImplementation: nodeImplementationOf<MorphDeclaration> =
 					return throwParseError("Invalid intersection of morphs")
 				const inTersection = intersectNodes(l.in, r.in, ctx)
 				if (inTersection instanceof Disjoint) return inTersection
-				const out =
-					l.out ?
-						r.out ?
-							intersectNodes(l.out, r.out, ctx)
-						:	l.out
-					:	r.out
-				if (out instanceof Disjoint) return out
+
 				// in case from is a union, we need to distribute the branches
 				// to can be a union as any schema is allowed
 				return ctx.$.schema(
 					inTersection.branches.map(inBranch =>
 						ctx.$.node("morph", {
 							morphs: l.morphs,
-							in: inBranch,
-							out
+							in: inBranch
 						})
 					)
 				)
@@ -150,22 +134,14 @@ export const morphImplementation: nodeImplementationOf<MorphDeclaration> =
 	})
 
 export class MorphNode extends BaseRoot<MorphDeclaration> {
-	serializedMorphs: string[] = (this.json as any).morphs
+	serializedMorphs: string[] = this.morphs.map(registeredReference)
 	compiledMorphs = `[${this.serializedMorphs}]`
-	outValidator: TraverseApply | null = this.inner.out?.traverseApply ?? null
-
-	private queueArgs: Parameters<TraversalContext["queueMorphs"]> = [
-		this.morphs,
-		this.outValidator ? { outValidator: this.outValidator } : {}
-	]
-
-	private queueArgsReference = registeredReference(this.queueArgs)
 
 	traverseAllows: TraverseAllows = (data, ctx) =>
 		this.in.traverseAllows(data, ctx)
 
 	traverseApply: TraverseApply = (data, ctx) => {
-		ctx.queueMorphs(...this.queueArgs)
+		ctx.queueMorphs(this.morphs)
 		this.in.traverseApply(data, ctx)
 	}
 
@@ -176,7 +152,7 @@ export class MorphNode extends BaseRoot<MorphDeclaration> {
 			js.return(js.invoke(this.in))
 			return
 		}
-		js.line(`ctx.queueMorphs(...${this.queueArgsReference})`)
+		js.line(`ctx.queueMorphs(${this.compiledMorphs})`)
 		js.line(js.invoke(this.in))
 	}
 
@@ -184,8 +160,15 @@ export class MorphNode extends BaseRoot<MorphDeclaration> {
 		return this.inner.in
 	}
 
+	get validatedOut(): BaseRoot | undefined {
+		const lastMorph = this.inner.morphs.at(-1)
+		return hasArkKind(lastMorph, "root") ?
+				(lastMorph?.out as BaseRoot)
+			:	undefined
+	}
+
 	override get out(): BaseRoot {
-		return (this.inner.out?.out as BaseRoot) ?? this.$.keywords.unknown.raw
+		return this.validatedOut ?? this.$.keywords.unknown.raw
 	}
 
 	rawKeyOf(): BaseRoot {
diff --git a/ark/schema/roots/proto.ts b/ark/schema/roots/proto.ts
index 4da828d269..09501ff9e8 100644
--- a/ark/schema/roots/proto.ts
+++ b/ark/schema/roots/proto.ts
@@ -1,14 +1,14 @@
 import {
-	type BuiltinObjectKind,
-	type Constructor,
-	type Key,
-	type array,
 	builtinConstructors,
 	constructorExtends,
 	getExactBuiltinConstructorName,
 	objectKindDescriptions,
 	objectKindOrDomainOf,
-	prototypeKeysOf
+	prototypeKeysOf,
+	type BuiltinObjectKind,
+	type Constructor,
+	type Key,
+	type array
 } from "@arktype/util"
 import type { BaseMeta, declareNode } from "../shared/declare.js"
 import { Disjoint } from "../shared/disjoint.js"
@@ -19,6 +19,7 @@ import {
 } from "../shared/implement.js"
 import type { TraverseAllows } from "../shared/traversal.js"
 import { RawBasis } from "./basis.js"
+import type { DomainNode } from "./domain.js"
 
 export interface ProtoInner<proto extends Constructor = Constructor>
 	extends BaseMeta {
@@ -81,7 +82,11 @@ export const protoImplementation: nodeImplementationOf<ProtoDeclaration> =
 			domain: (proto, domain, ctx) =>
 				domain.domain === "object" ?
 					proto
-				:	Disjoint.from("domain", ctx.$.keywords.object as never, domain)
+				:	Disjoint.from(
+						"domain",
+						ctx.$.keywords.object.raw as DomainNode,
+						domain
+					)
 		}
 	})
 
diff --git a/ark/schema/roots/root.ts b/ark/schema/roots/root.ts
index 17370d8d30..360a20c364 100644
--- a/ark/schema/roots/root.ts
+++ b/ark/schema/roots/root.ts
@@ -230,7 +230,7 @@ export abstract class BaseRoot<
 						omit(inner as StructureInner, { undeclared: 1 })
 					:	{ ...inner, undeclared }
 				:	inner,
-			node => !includes(structuralKinds, node.kind)
+			{ shouldTransform: node => !includes(structuralKinds, node.kind) }
 		)
 	}
 
diff --git a/ark/schema/roots/union.ts b/ark/schema/roots/union.ts
index d749204139..d25242c31c 100644
--- a/ark/schema/roots/union.ts
+++ b/ark/schema/roots/union.ts
@@ -1,8 +1,26 @@
-import { appendUnique, groupBy, isArray, type array } from "@arktype/util"
+import {
+	appendUnique,
+	cached,
+	compileLiteralPropAccess,
+	domainDescriptions,
+	entriesOf,
+	flatMorph,
+	groupBy,
+	isArray,
+	isKeyOf,
+	printable,
+	throwInternalError,
+	type Domain,
+	type Json,
+	type SerializedPrimitive,
+	type array,
+	type keySet,
+	type show
+} from "@arktype/util"
 import type { Node, NodeSchema } from "../kinds.js"
 import type { NodeCompiler } from "../shared/compile.js"
 import type { BaseMeta, declareNode } from "../shared/declare.js"
-import { Disjoint } from "../shared/disjoint.js"
+import { Disjoint, type SerializedPath } from "../shared/disjoint.js"
 import type { ArkError } from "../shared/errors.js"
 import {
 	implementNode,
@@ -13,7 +31,10 @@ import {
 } from "../shared/implement.js"
 import { intersectNodes, intersectNodesRoot } from "../shared/intersections.js"
 import type { TraverseAllows, TraverseApply } from "../shared/traversal.js"
+import type { TraversalPath } from "../shared/utils.js"
+import type { DomainInner, DomainNode } from "./domain.js"
 import { BaseRoot, type schemaKindRightOf } from "./root.js"
+import type { UnitNode } from "./unit.js"
 import { defineRightwardIntersections } from "./utils.js"
 
 export type UnionChildKind = schemaKindRightOf<"union"> | "alias"
@@ -94,9 +115,8 @@ export const unionImplementation: nodeImplementationOf<UnionDeclaration> =
 			)
 		},
 		defaults: {
-			description: node => {
-				return describeBranches(node.branches.map(branch => branch.description))
-			},
+			description: node =>
+				describeBranches(node.branches.map(branch => branch.description)),
 			expected: ctx => {
 				const byPath = groupBy(ctx.errors, "propString") as Record<
 					string,
@@ -111,13 +131,12 @@ export const unionImplementation: nodeImplementationOf<UnionDeclaration> =
 							appendUnique(branchesAtPath, errorAtPath.expected)
 						)
 						const expected = describeBranches(branchesAtPath)
-						const actual = errors.reduce(
-							(acc, e) =>
-								e.actual && !acc.includes(e.actual) ?
-									`${acc && `${acc}, `}${e.actual}`
-								:	acc,
-							""
-						)
+						// if there are multiple actual descriptions that differ,
+						// just fall back to printable, which is the most specific
+						const actual =
+							errors.every(e => e.actual === errors[0].actual) ?
+								errors[0].actual
+							:	printable(errors[0].data)
 						return `${path && `${path} `}must be ${expected}${
 							actual && ` (was ${actual})`
 						}`
@@ -173,7 +192,12 @@ export class UnionNode extends BaseRoot<UnionDeclaration> {
 		this.branches[0].hasUnit(false) &&
 		this.branches[1].hasUnit(true)
 
-	discriminant = null
+	unitBranches = this.branches.filter((n): n is UnitNode => n.hasKind("unit"))
+
+	discriminant = this.discriminate()
+	discriminantJson =
+		this.discriminant ? discriminantToJson(this.discriminant) : null
+
 	expression: string =
 		this.isNever ? "never"
 		: this.isBoolean ? "boolean"
@@ -195,6 +219,54 @@ export class UnionNode extends BaseRoot<UnionDeclaration> {
 	}
 
 	compile(js: NodeCompiler): void {
+		if (
+			!this.discriminant ||
+			// if we have a union of two units like `boolean`, the
+			// undiscriminated compilation will be just as fast
+			(this.unitBranches.length === this.branches.length &&
+				this.branches.length === 2)
+		)
+			return this.compileIndiscriminable(js)
+
+		// we need to access the path as optional so we don't throw if it isn't present
+		const condition = this.discriminant.path.reduce(
+			(acc, segment) => acc + compileLiteralPropAccess(segment, true),
+			this.discriminant.kind === "domain" ? "typeof data" : "data"
+		)
+
+		const cases = this.discriminant.cases
+
+		const caseKeys = Object.keys(cases)
+
+		js.block(`switch(${condition})`, () => {
+			for (const k in cases) {
+				const v = cases[k]
+				const caseCondition = k === "default" ? "default" : `case ${k}`
+				js.line(`${caseCondition}: return ${v === true ? v : js.invoke(v)}`)
+			}
+
+			return js
+		})
+
+		if (js.traversalKind === "Allows") {
+			js.return(false)
+			return
+		}
+
+		const expected = describeBranches(
+			this.discriminant.kind === "domain" ?
+				caseKeys.map(k => domainDescriptions[k.slice(1, -1) as Domain])
+			:	caseKeys
+		)
+
+		js.line(`ctx.error({
+	expected: ${JSON.stringify(expected)},
+	actual: ${condition},
+	relativePath: ${JSON.stringify(this.discriminant.path)}
+})`)
+	}
+
+	private compileIndiscriminable(js: NodeCompiler): void {
 		if (js.traversalKind === "Apply") {
 			js.const("errors", "[]")
 			this.branches.forEach(branch =>
@@ -227,8 +299,123 @@ export class UnionNode extends BaseRoot<UnionDeclaration> {
 		// already collapsed to a single keyword
 		return this.isBoolean ? "boolean" : super.nestableExpression
 	}
+
+	@cached
+	discriminate(): Discriminant | null {
+		if (this.branches.length < 2) return null
+		if (this.unitBranches.length === this.branches.length) {
+			const cases = flatMorph(this.unitBranches, (i, unit) => [
+				`${unit.serializedValue}`,
+				true as const
+			])
+
+			return {
+				path: [],
+				kind: "unit",
+				cases
+			}
+		}
+		const casesBySpecifier: CasesBySpecifier = {}
+		for (let lIndex = 0; lIndex < this.branches.length - 1; lIndex++) {
+			const l = this.branches[lIndex]
+			for (let rIndex = lIndex + 1; rIndex < this.branches.length; rIndex++) {
+				const r = this.branches[rIndex]
+				const result = intersectNodesRoot(l, r, l.$)
+				if (!(result instanceof Disjoint)) continue
+
+				for (const { path, kind, disjoint } of result.flat) {
+					if (!isKeyOf(kind, discriminantKinds)) continue
+
+					const qualifiedDiscriminant: DiscriminantKey = `${path}${kind}`
+					let lSerialized: string
+					let rSerialized: string
+					if (kind === "domain") {
+						lSerialized = `"${(disjoint.l as DomainNode).domain}"`
+						rSerialized = `"${(disjoint.r as DomainNode).domain}"`
+					} else if (kind === "unit") {
+						lSerialized = (disjoint.l as UnitNode).serializedValue as never
+						rSerialized = (disjoint.r as UnitNode).serializedValue as never
+					} else {
+						return throwInternalError(
+							`Unexpected attempt to discriminate disjoint kind '${kind}'`
+						)
+					}
+					if (!casesBySpecifier[qualifiedDiscriminant]) {
+						casesBySpecifier[qualifiedDiscriminant] = {
+							[lSerialized]: [l],
+							[rSerialized]: [r]
+						}
+						continue
+					}
+					const cases = casesBySpecifier[qualifiedDiscriminant]!
+					if (!isKeyOf(lSerialized, cases)) cases[lSerialized] = [l]
+					else if (!cases[lSerialized].includes(l)) cases[lSerialized].push(l)
+
+					if (!isKeyOf(rSerialized, cases)) cases[rSerialized] = [r]
+					else if (!cases[rSerialized].includes(r)) cases[rSerialized].push(r)
+				}
+			}
+		}
+
+		const bestDiscriminantEntry = entriesOf(casesBySpecifier)
+			.sort((a, b) => Object.keys(a[1]).length - Object.keys(b[1]).length)
+			.at(-1)
+
+		if (!bestDiscriminantEntry) return null
+
+		const [specifier, bestCases] = bestDiscriminantEntry
+		const [path, kind] = parseDiscriminantKey(specifier)
+
+		let defaultBranches = [...this.branches]
+
+		const cases = flatMorph(bestCases, (k, caseBranches) => {
+			const prunedBranches: BaseRoot[] = []
+			defaultBranches = defaultBranches.filter(n => !caseBranches.includes(n))
+			for (const branch of caseBranches) {
+				const pruned = pruneDiscriminant(kind, path, branch)
+				// if any branch of the union has no constraints (i.e. is unknown)
+				// return it right away
+				if (pruned === null) return [k, true as const]
+				prunedBranches.push(pruned)
+			}
+
+			const caseNode =
+				prunedBranches.length === 1 ?
+					prunedBranches[0]
+				:	this.$.node("union", prunedBranches)
+
+			Object.assign(this.referencesById, caseNode.referencesById)
+
+			return [k, caseNode]
+		})
+
+		if (defaultBranches.length) {
+			cases.default = this.$.node("union", defaultBranches, {
+				prereduced: true
+			})
+
+			Object.assign(this.referencesById, cases.default.referencesById)
+		}
+
+		return {
+			kind,
+			path,
+			cases
+		}
+	}
 }
 
+const discriminantToJson = (discriminant: Discriminant): Json => ({
+	kind: discriminant.kind,
+	path: discriminant.path,
+	cases: flatMorph(discriminant.cases, (k, node) => [
+		k,
+		node === true ? node
+		: node.hasKind("union") && node.discriminantJson ? node.discriminantJson
+		: node.json
+	])
+})
+
 const describeBranches = (descriptions: string[]) => {
 	if (descriptions.length === 0) return "never"
 
@@ -249,84 +436,6 @@ const describeBranches = (descriptions: string[]) => {
 	return description
 }
 
-// 	private static compileDiscriminatedLiteral(cases: DiscriminatedCases) {
-// 		// TODO: error messages for traversal
-// 		const caseKeys = Object.keys(cases)
-// 		if (caseKeys.length === 2) {
-// 			return `if( ${this.argName} !== ${caseKeys[0]} && ${this.argName} !== ${caseKeys[1]}) {
-//     return false
-// }`
-// 		}
-// 		// for >2 literals, we fall through all cases, breaking on the last
-// 		const compiledCases =
-// 			caseKeys.map((k) => `    case ${k}:`).join("\n") + "        break"
-// 		// if none of the cases are met, the check fails (this is optimal for perf)
-// 		return `switch(${this.argName}) {
-//     ${compiledCases}
-//     default:
-//         return false
-// }`
-// 	}
-
-// 	private static compileIndiscriminable(
-// 		branches: readonly BranchNode[],
-// 		ctx: CompilationContext
-// 	) {
-// 		if (branches.length === 0) {
-// 			return compileFailureResult("custom", "nothing", ctx)
-// 		}
-// 		if (branches.length === 1) {
-// 			return branches[0].compile(ctx)
-// 		}
-// 		return branches
-// 			.map(
-// 				(branch) => `(() => {
-// 	${branch.compile(ctx)}
-// 	return true
-// 	})()`
-// 			)
-// 			.join(" || ")
-// 	}
-
-// 	private static compileDiscriminant(
-// 		discriminant: Discriminant,
-// 		ctx: CompilationContext
-// 	) {
-// 		if (discriminant.isPureRootLiteral) {
-// 			// TODO: ctx?
-// 			return this.compileDiscriminatedLiteral(discriminant.cases)
-// 		}
-// 		let compiledPath = this.argName
-// 		for (const segment of discriminant.path) {
-// 			// we need to access the path as optional so we don't throw if it isn't present
-// 			compiledPath += compilePropAccess(segment, true)
-// 		}
-// 		const condition =
-// 			discriminant.kind === "domain" ? `typeof ${compiledPath}` : compiledPath
-// 		let compiledCases = ""
-// 		for (const k in discriminant.cases) {
-// 			const caseCondition = k === "default" ? "default" : `case ${k}`
-// 			const caseBranches = discriminant.cases[k]
-// 			ctx.discriminants.push(discriminant)
-// 			const caseChecks = isArray(caseBranches)
-// 				? this.compileIndiscriminable(caseBranches, ctx)
-// 				: this.compileDiscriminant(caseBranches, ctx)
-// 			ctx.discriminants.pop()
-// 			compiledCases += `${caseCondition}: {
-// 		${caseChecks ? `${caseChecks}\n     break` : "break"}
-// 	}`
-// 		}
-// 		if (!discriminant.cases.default) {
-// 			// TODO: error message for traversal
-// 			compiledCases += `default: {
-// 		return false
-// 	}`
-// 		}
-// 		return `switch(${condition}) {
-// 		${compiledCases}
-// 	}`
-// 	}
-
 export const intersectBranches = (
 	l: readonly UnionChildNode[],
 	r: readonly UnionChildNode[],
@@ -430,3 +539,86 @@ export const reduceBranches = ({
 	}
 	return branches.filter((_, i) => uniquenessByIndex[i])
 }
+
+export type CaseKey<kind extends DiscriminantKind = DiscriminantKind> =
+	DiscriminantKind extends kind ? string : DiscriminantKinds[kind] | "default"
+
+export type Discriminant<kind extends DiscriminantKind = DiscriminantKind> = {
+	path: string[]
+	kind: kind
+	cases: DiscriminatedCases<kind>
+}
+
+export type DiscriminatedCases<
+	kind extends DiscriminantKind = DiscriminantKind
+> = {
+	[caseKey in CaseKey<kind>]: BaseRoot | true
+}
+
+type DiscriminantKey = `${SerializedPath}${DiscriminantKind}`
+
+type CasesBySpecifier = {
+	[k in DiscriminantKey]?: Record<string, BaseRoot[]>
+}
+
+export type DiscriminantKinds = {
+	domain: Domain
+	unit: SerializedPrimitive
+}
+
+const discriminantKinds: keySet<DiscriminantKind> = {
+	domain: 1,
+	unit: 1
+}
+
+export type DiscriminantKind = show<keyof DiscriminantKinds>
+
+const parseDiscriminantKey = (key: DiscriminantKey) => {
+	const lastPathIndex = key.lastIndexOf("]")
+	const parsedPath: string[] = JSON.parse(key.slice(0, lastPathIndex + 1))
+	const parsedKind: DiscriminantKind = key.slice(lastPathIndex + 1) as never
+	return [parsedPath, parsedKind] as const
+}
+
+export const pruneDiscriminant = (
+	discriminantKind: DiscriminantKind,
+	path: TraversalPath,
+	branch: BaseRoot
+): BaseRoot | null =>
+	branch.transform(
+		(nodeKind, inner, ctx) => {
+			// if we've already checked a path at least as long as the current one,
+			// we don't need to revalidate that we're in an object
+			if (
+				nodeKind === "domain" &&
+				(inner as DomainInner).domain === "object" &&
+				path.length > ctx.path.length
+			)
+				return null
+
+			// if the discriminant has already checked the domain at the current path
+			// (or an exact value, implying a domain), we don't need to recheck it
+			if (
+				(discriminantKind === nodeKind ||
+					(nodeKind === "domain" && ctx.path.length === path.length)) &&
+				ctx.path.length === path.length &&
+				ctx.path.every((segment, i) => segment === path[i])
+			)
+				return null
+			return inner
+		},
+		{
+			shouldTransform: node =>
+				node.children.length !== 0 ||
+				node.kind === "domain" ||
+				node.kind === "unit"
+		}
+	)
+
+// // TODO: if deeply includes morphs?
+// const writeUndiscriminableMorphUnionMessage = <path extends string>(
+// 	path: path
+// ) =>
+// 	`${
+// 		path === "/" ? "A" : `At ${path}, a`
+// 	} union including one or more morphs must be discriminable` as const
diff --git a/ark/schema/roots/unit.ts b/ark/schema/roots/unit.ts
index 35878b9f3b..231b47e3c0 100644
--- a/ark/schema/roots/unit.ts
+++ b/ark/schema/roots/unit.ts
@@ -55,7 +55,17 @@ export const unitImplementation: nodeImplementationOf<UnitDeclaration> =
 		intersections: {
 			unit: (l, r) => Disjoint.from("unit", l, r),
 			...defineRightwardIntersections("unit", (l, r) =>
-				r.allows(l.unit) ? l : Disjoint.from("assignability", l.unit, r)
+				r.allows(l.unit) ? l : (
+					Disjoint.from(
+						"assignability",
+						l,
+						r.hasKind("intersection") ?
+							r.children.find(
+								rConstraint => !rConstraint.allows(l.unit as never)
+							)!
+						:	r
+					)
+				)
 			)
 		}
 	})
diff --git a/ark/schema/scope.ts b/ark/schema/scope.ts
index 172592d59a..e38e362580 100644
--- a/ark/schema/scope.ts
+++ b/ark/schema/scope.ts
@@ -2,6 +2,7 @@ import {
 	CompiledFunction,
 	DynamicBase,
 	bound,
+	envHasCsp,
 	flatMorph,
 	hasDomain,
 	isArray,
@@ -135,7 +136,7 @@ export const defaultConfig: ResolvedArkConfig = Object.assign(
 		implementation.defaults
 	]),
 	{
-		jitless: false,
+		jitless: envHasCsp(),
 		registerKeywords: false,
 		prereducedAliases: false
 	} satisfies Omit<ResolvedArkConfig, NodeKind>
@@ -388,12 +389,11 @@ export class RawRootScope<$ extends RawRootResolutions = RawRootResolutions>
 			if (this.resolved) {
 				// this node was not part of the original scope, so compile an anonymous scope
 				// including only its references
-				if (!this.resolvedConfig.jitless)
-					bindCompiledScope(node.contributesReferences)
+				if (!this.resolvedConfig.jitless) bindCompiledScope(node.references)
 			} else {
 				// we're still parsing the scope itself, so defer compilation but
 				// add the node as a reference
-				Object.assign(this.referencesById, node.contributesReferencesById)
+				Object.assign(this.referencesById, node.referencesById)
 			}
 
 			return node as never
@@ -699,8 +699,8 @@ export const bindCompiledScope = (references: readonly BaseNode[]): void => {
 	}
 }
 
-const compileScope = (references: readonly BaseNode[]) => {
-	return new CompiledFunction()
+const compileScope = (references: readonly BaseNode[]) =>
+	new CompiledFunction()
 		.block("return", js => {
 			references.forEach(node => {
 				const allowsCompiler = new NodeCompiler("Allows").indent()
@@ -719,4 +719,3 @@ const compileScope = (references: readonly BaseNode[]) => {
 				[k: `${string}Apply`]: TraverseApply
 			}
 		>()()
-}
diff --git a/ark/schema/shared/compile.ts b/ark/schema/shared/compile.ts
index d4787a0b16..16365f11f1 100644
--- a/ark/schema/shared/compile.ts
+++ b/ark/schema/shared/compile.ts
@@ -1,8 +1,6 @@
 import { CompiledFunction } from "@arktype/util"
-import type { Node } from "../kinds.js"
 import type { BaseNode } from "../node.js"
-import type { Discriminant } from "../roots/discriminate.js"
-import type { PrimitiveKind } from "./implement.js"
+import type { Discriminant } from "../roots/union.js"
 import type { TraversalKind } from "./traversal.js"
 
 export interface InvokeOptions extends ReferenceOptions {
@@ -76,39 +74,6 @@ export class NodeCompiler extends CompiledFunction<["data", "ctx"]> {
 			:	this.line(this.invoke(node, opts))
 	}
 
-	compilePrimitive(node: Node<PrimitiveKind>): this {
-		const pathString = this.path.join()
-		if (
-			node.kind === "domain" &&
-			node.domain === "object" &&
-			this.discriminants.some(d => d.path.join().startsWith(pathString))
-		) {
-			// if we've already checked a path at least as long as the current one,
-			// we don't need to revalidate that we're in an object
-			return this
-		}
-		if (
-			(node.kind === "domain" || node.kind === "unit") &&
-			this.discriminants.some(
-				d =>
-					d.path.join() === pathString &&
-					(node.kind === "domain" ?
-						d.kind === "domain" || d.kind === "value"
-					:	d.kind === "value")
-			)
-		) {
-			// if the discriminant has already checked the domain at the current path
-			// (or an exact value, implying a domain), we don't need to recheck it
-			return this
-		}
-		if (this.traversalKind === "Allows")
-			return this.return(node.compiledCondition)
-
-		return this.if(node.compiledNegation, () =>
-			this.line(`${this.ctx}.error(${node.compiledErrorContext})`)
-		)
-	}
-
 	writeMethod(name: string): string {
 		return `${name}(${this.argNames.join(", ")}){\n${this.body}    }\n`
 	}
diff --git a/ark/schema/shared/disjoint.ts b/ark/schema/shared/disjoint.ts
index d764ed614c..0b3525edc7 100644
--- a/ark/schema/shared/disjoint.ts
+++ b/ark/schema/shared/disjoint.ts
@@ -10,8 +10,9 @@ import {
 	type entryOf
 } from "@arktype/util"
 import type { Node } from "../kinds.js"
+import type { BaseNode } from "../node.js"
 import type { BaseRoot } from "../roots/root.js"
-import type { BoundKind, PrimitiveKind } from "./implement.js"
+import type { BoundKind } from "./implement.js"
 import { hasArkKind } from "./utils.js"
 
 type DisjointKinds = {
@@ -35,15 +36,11 @@ type DisjointKinds = {
 		l: Node<BoundKind>
 		r: Node<BoundKind>
 	}
-	assignability?:
-		| {
-				l: unknown
-				r: Node<PrimitiveKind>
-		  }
-		| {
-				l: Node<PrimitiveKind>
-				r: unknown
-		  }
+	// exactly one of l or r should be a UnitNode
+	assignability?: {
+		l: BaseNode
+		r: BaseNode
+	}
 	union?: {
 		l: readonly BaseRoot[]
 		r: readonly BaseRoot[]
diff --git a/ark/schema/shared/intersections.ts b/ark/schema/shared/intersections.ts
index 8d2ce4ee43..804c02bc59 100644
--- a/ark/schema/shared/intersections.ts
+++ b/ark/schema/shared/intersections.ts
@@ -166,12 +166,17 @@ export const pipeFromMorph = (
 	to: BaseRoot,
 	ctx: IntersectionContext
 ): MorphNode | Disjoint => {
-	const out = from?.out ? intersectNodes(from.out, to, ctx) : to
-	if (out instanceof Disjoint) return out
+	const morphs = [...from.morphs]
+	if (from.validatedOut) {
+		// still piped from context, so allows appending additional morphs
+		const outIntersection = intersectNodes(from.validatedOut, to, ctx)
+		if (outIntersection instanceof Disjoint) return outIntersection
+		morphs[morphs.length - 1] = outIntersection
+	} else morphs.push(to)
+
 	return ctx.$.node("morph", {
-		morphs: from.morphs,
-		in: from.in,
-		out
+		morphs,
+		in: from.in
 	})
 }
 
@@ -184,7 +189,6 @@ export const pipeToMorph = (
 	if (result instanceof Disjoint) return result
 	return ctx.$.node("morph", {
 		morphs: to.morphs,
-		in: result,
-		out: to.out
+		in: result
 	})
 }
diff --git a/ark/schema/shared/traversal.ts b/ark/schema/shared/traversal.ts
index 678f3cfa1f..4e93171c94 100644
--- a/ark/schema/shared/traversal.ts
+++ b/ark/schema/shared/traversal.ts
@@ -13,7 +13,6 @@ import type { TraversalPath } from "./utils.js"
 export type QueuedMorphs = {
 	path: TraversalPath
 	morphs: array<Morph>
-	to?: TraverseApply
 }
 
 export type BranchTraversalContext = {
@@ -21,10 +20,6 @@ export type BranchTraversalContext = {
 	queuedMorphs: QueuedMorphs[]
 }
 
-export type QueueMorphOptions = {
-	outValidator?: TraverseApply
-}
-
 export class TraversalContext {
 	path: TraversalPath = []
 	queuedMorphs: QueuedMorphs[] = []
@@ -42,12 +37,11 @@ export class TraversalContext {
 		return this.branches.at(-1)
 	}
 
-	queueMorphs(morphs: array<Morph>, opts?: QueueMorphOptions): void {
+	queueMorphs(morphs: array<Morph>): void {
 		const input: QueuedMorphs = {
 			path: [...this.path],
 			morphs
 		}
-		if (opts?.outValidator) input.to = opts?.outValidator
 		this.currentBranch?.queuedMorphs.push(input) ??
 			this.queuedMorphs.push(input)
 	}
@@ -58,46 +52,35 @@ export class TraversalContext {
 		let out: any = this.root
 		if (this.queuedMorphs.length) {
 			for (let i = 0; i < this.queuedMorphs.length; i++) {
-				const { path, morphs, to } = this.queuedMorphs[i]
-				if (path.length === 0) {
-					this.path = []
-					// if the morph applies to the root, just assign to it directly
-					for (const morph of morphs) {
-						const result = morph(out, this)
-						if (result instanceof ArkErrors) return result
-						if (this.hasError()) return this.errors
-						if (result instanceof ArkError) {
-							// if an ArkTypeError was returned but wasn't added to these
-							// errors, add it then return
-							this.error(result)
-							return this.errors
-						}
-						out = result
-					}
-				} else {
+				const { path, morphs } = this.queuedMorphs[i]
+
+				const key = path.at(-1)
+
+				let parent: any
+
+				if (key !== undefined) {
 					// find the object on which the key to be morphed exists
-					let parent = out
+					parent = out
 					for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++)
 						parent = parent[path[pathIndex]]
+				}
 
-					// apply the morph function and assign the result to the corresponding property
-					const key = path.at(-1)!
-					this.path = path
-					for (const morph of morphs) {
-						const result = morph(parent[key], this)
-						if (result instanceof ArkErrors) return result
-						if (this.hasError()) return this.errors
-						if (result instanceof ArkError) {
-							this.error(result)
-							return this.errors
-						}
-						parent[key] = result
+				this.path = path
+				for (const morph of morphs) {
+					const result = morph(parent === undefined ? out : parent[key!], this)
+					if (result instanceof ArkErrors) return result
+					if (this.hasError()) return this.errors
+					if (result instanceof ArkError) {
+						// if an ArkError was returned but wasn't added to these
+						// errors, add it then return
+						this.error(result)
+						return this.errors
 					}
-				}
-				if (to) {
-					const toCtx = new TraversalContext(out, this.config)
-					to(out, toCtx)
-					return toCtx.finalize()
+
+					// apply the morph function and assign the result to the
+					// corresponding property, or to root if path is empty
+					if (parent === undefined) out = result
+					else parent[key!] = result
 				}
 			}
 		}
diff --git a/ark/schema/structure/index.ts b/ark/schema/structure/index.ts
index ff2169f535..1b07510840 100644
--- a/ark/schema/structure/index.ts
+++ b/ark/schema/structure/index.ts
@@ -5,6 +5,10 @@ import {
 } from "@arktype/util"
 import { BaseConstraint } from "../constraint.js"
 import type { Node, RootSchema } from "../kinds.js"
+import type {
+	DeepNodeTransformation,
+	DeepNodeTransformationContext
+} from "../node.js"
 import type { BaseRoot } from "../roots/root.js"
 import type { UnitNode } from "../roots/unit.js"
 import type { BaseMeta, declareNode } from "../shared/declare.js"
@@ -129,6 +133,16 @@ export class IndexNode extends BaseConstraint<IndexDeclaration> {
 			}
 		})
 
+	protected override _transform(
+		mapper: DeepNodeTransformation,
+		ctx: DeepNodeTransformationContext
+	) {
+		ctx.path.push(this.signature)
+		const result = super._transform(mapper, ctx)
+		ctx.path.pop()
+		return result
+	}
+
 	compile(): void {
 		// this is currently handled by StructureNode
 	}
diff --git a/ark/schema/structure/prop.ts b/ark/schema/structure/prop.ts
index 77eae2f390..5e70f942c6 100644
--- a/ark/schema/structure/prop.ts
+++ b/ark/schema/structure/prop.ts
@@ -8,6 +8,10 @@ import {
 } from "@arktype/util"
 import { BaseConstraint } from "../constraint.js"
 import type { Node, RootSchema } from "../kinds.js"
+import type {
+	DeepNodeTransformation,
+	DeepNodeTransformationContext
+} from "../node.js"
 import type { Morph } from "../roots/morph.js"
 import type { BaseRoot } from "../roots/root.js"
 import type { NodeCompiler } from "../shared/compile.js"
@@ -92,6 +96,16 @@ export abstract class BaseProp<
 	compiledKey: string =
 		typeof this.key === "string" ? this.key : this.serializedKey
 
+	protected override _transform(
+		mapper: DeepNodeTransformation,
+		ctx: DeepNodeTransformationContext
+	) {
+		ctx.path.push(this.key)
+		const result = super._transform(mapper, ctx)
+		ctx.path.pop()
+		return result
+	}
+
 	private defaultValueMorphs: Morph[] = [
 		data => {
 			data[this.key] = (this as OptionalNode).default
diff --git a/ark/schema/structure/sequence.ts b/ark/schema/structure/sequence.ts
index 7474e1bdec..61422ec9fe 100644
--- a/ark/schema/structure/sequence.ts
+++ b/ark/schema/structure/sequence.ts
@@ -8,6 +8,10 @@ import {
 } from "@arktype/util"
 import { BaseConstraint } from "../constraint.js"
 import type { MutableInner, RootSchema } from "../kinds.js"
+import type {
+	DeepNodeTransformation,
+	DeepNodeTransformationContext
+} from "../node.js"
 import type { MaxLengthNode } from "../refinements/maxLength.js"
 import type { MinLengthNode } from "../refinements/minLength.js"
 import type { BaseRoot } from "../roots/root.js"
@@ -309,6 +313,16 @@ export class SequenceNode extends BaseConstraint<SequenceDeclaration> {
 		if (js.traversalKind === "Allows") js.return(true)
 	}
 
+	protected override _transform(
+		mapper: DeepNodeTransformation,
+		ctx: DeepNodeTransformationContext
+	) {
+		ctx.path.push(this.$.keywords.nonNegativeIntegerString.raw)
+		const result = super._transform(mapper, ctx)
+		ctx.path.pop()
+		return result
+	}
+
 	tuple: SequenceTuple = sequenceInnerToTuple(this.inner)
 	// this depends on tuple so needs to come after it
 	expression: string = this.description
diff --git a/ark/type/__tests__/discrimination.test.ts b/ark/type/__tests__/discrimination.test.ts
index 416a75ad69..2ac60e80ec 100644
--- a/ark/type/__tests__/discrimination.test.ts
+++ b/ark/type/__tests__/discrimination.test.ts
@@ -1,50 +1,94 @@
-// import { attest } from "@arktype/attest"
-// import { scope, type } from "arktype"
+import { attest, contextualize } from "@arktype/attest"
+import { scope, type } from "arktype"
 
-describe("discrimination", () => {
-	// it("2 literal branches", () => {
-	// 	// should not use a switch with <=2 branches to avoid visual clutter
-	// 	const t = type("'a'|'b'")
-	// 	attest(t.json).snap({ unit: "a" })
-	// 	attest(t.allows("a")).equals(true)
-	// 	attest(t.allows("b")).equals(true)
-	// 	attest(t.allows("c")).equals(false)
-	// })
-	// it(">2 literal branches", () => {
-	// 	const t = type("'a'|'b'|'c'")
-	// 	attest(t.json).snap({ unit: "a" })
-	// 	attest(t.allows("a")).equals(true)
-	// 	attest(t.allows("b")).equals(true)
-	// 	attest(t.allows("c")).equals(true)
-	// 	attest(t.allows("d")).equals(false)
-	// })
-	// const getPlaces = () =>
-	// 	scope({
-	// 		rainForest: {
-	// 			climate: "'wet'",
-	// 			color: "'green'",
-	// 			isRainForest: "true"
-	// 		},
-	// 		desert: { climate: "'dry'", color: "'brown'", isDesert: "true" },
-	// 		sky: { climate: "'dry'", color: "'blue'", isSky: "true" },
-	// 		ocean: { climate: "'wet'", color: "'blue'", isOcean: "true" }
-	// 	})
-	// it("nested", () => {
-	// 	const t = getPlaces().type("ocean|sky|rainForest|desert")
-	// 	attest(t.json).snap()
-	// })
-	// it("undiscriminable", () => {
-	// 	const t = getPlaces().type([
-	// 		"ocean",
-	// 		"|",
-	// 		{
-	// 			climate: "'wet'",
-	// 			color: "'blue'",
-	// 			indistinguishableFrom: "ocean"
-	// 		}
-	// 	])
-	// })
-	// it("doesn't discriminate optional key", () => {
+contextualize(() => {
+	it("2 literal branches", () => {
+		// should not use a switch with <=2 branches to avoid visual clutter
+		const t = type("'a'|'b'")
+		attest(t.json).snap([{ unit: "a" }, { unit: "b" }])
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).snap({
+			kind: "unit",
+			path: [],
+			cases: { '"a"': true, '"b"': true }
+		})
+		attest(t.allows("a")).equals(true)
+		attest(t.allows("b")).equals(true)
+		attest(t.allows("c")).equals(false)
+	})
+
+	it(">2 literal branches", () => {
+		const t = type("'a'|'b'|'c'")
+		attest(t.json).snap([{ unit: "a" }, { unit: "b" }, { unit: "c" }])
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).snap({
+			kind: "unit",
+			path: [],
+			cases: { '"a"': true, '"b"': true, '"c"': true }
+		})
+		attest(t.allows("a")).equals(true)
+		attest(t.allows("b")).equals(true)
+		attest(t.allows("c")).equals(true)
+		attest(t.allows("d")).equals(false)
+	})
+
+	const getPlaces = () =>
+		scope({
+			rainForest: {
+				climate: "'wet'",
+				color: "'green'",
+				isRainForest: "true"
+			},
+			desert: { climate: "'dry'", color: "'brown'", isDesert: "true" },
+			sky: { climate: "'dry'", color: "'blue'", isSky: "true" },
+			ocean: { climate: "'wet'", color: "'blue'", isOcean: "true" }
+		})
+
+	it("nested", () => {
+		const $ = getPlaces()
+		const t = $.type("ocean|sky|rainForest|desert")
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).snap({
+			kind: "unit",
+			path: ["color"],
+			cases: {
+				'"blue"': {
+					kind: "unit",
+					path: ["climate"],
+					cases: {
+						'"dry"': { required: [{ key: "isSky", value: { unit: true } }] },
+						'"wet"': { required: [{ key: "isOcean", value: { unit: true } }] }
+					}
+				},
+				'"brown"': {
+					required: [
+						{ key: "climate", value: { unit: "dry" } },
+						{ key: "isDesert", value: { unit: true } }
+					]
+				},
+				'"green"': {
+					required: [
+						{ key: "climate", value: { unit: "wet" } },
+						{ key: "isRainForest", value: { unit: true } }
+					]
+				}
+			}
+		})
+	})
+
+	it("indiscriminable", () => {
+		const t = getPlaces().type([
+			"ocean",
+			"|",
+			{
+				climate: "'wet'",
+				color: "'blue'",
+				indistinguishableFrom: "ocean"
+			}
+		])
+
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).equals(null)
+	})
+
+	// https://github.com/arktypeio/arktype/issues/960
+	// it("discriminate optional key", () => {
 	// 	const t = type({
 	// 		direction: "'forward' | 'backward'",
 	// 		"operator?": "'by'"
@@ -52,23 +96,77 @@ describe("discrimination", () => {
 	// 		duration: "'s' | 'min' | 'h'",
 	// 		operator: "'to'"
 	// 	})
-	// 	attest(t.hasKind("union") && t.discriminant).equals(null)
-	// })
-	// it("default case", () => {
-	// 	const t = getPlaces().type([
-	// 		"ocean|rainForest",
-	// 		"|",
-	// 		{ temperature: "'hot'" }
-	// 	])
-	// })
-	// it("discriminable default", () => {
-	// 	const t = getPlaces().type([
-	// 		{ temperature: "'cold'" },
-	// 		"|",
-	// 		["ocean|rainForest", "|", { temperature: "'hot'" }]
-	// 	])
-	// })
-	// it("won't discriminate between possibly empty arrays", () => {
-	// 	const t = type("string[]|boolean[]")
+
+	// 	attest(t.raw.hasKind("union") && t.raw.discriminantJson).equals(null)
 	// })
+
+	it("default case", () => {
+		const t = getPlaces().type([
+			"ocean|rainForest",
+			"|",
+			{ temperature: "'hot'" }
+		])
+
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).snap({
+			kind: "unit",
+			path: ["color"],
+			cases: {
+				'"blue"': {
+					required: [
+						{ key: "climate", value: { unit: "wet" } },
+						{ key: "isOcean", value: { unit: true } }
+					]
+				},
+				'"green"': {
+					required: [
+						{ key: "climate", value: { unit: "wet" } },
+						{ key: "isRainForest", value: { unit: true } }
+					]
+				},
+				default: {
+					required: [{ key: "temperature", value: { unit: "hot" } }],
+					domain: "object"
+				}
+			}
+		})
+	})
+
+	it("discriminable default", () => {
+		const t = getPlaces().type([
+			{ temperature: "'cold'" },
+			"|",
+			["ocean|rainForest", "|", { temperature: "'hot'" }]
+		])
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).snap({
+			kind: "unit",
+			path: ["temperature"],
+			cases: {
+				'"cold"': true,
+				'"hot"': true,
+				default: {
+					kind: "unit",
+					path: ["color"],
+					cases: {
+						'"blue"': {
+							required: [
+								{ key: "climate", value: { unit: "wet" } },
+								{ key: "isOcean", value: { unit: true } }
+							]
+						},
+						'"green"': {
+							required: [
+								{ key: "climate", value: { unit: "wet" } },
+								{ key: "isRainForest", value: { unit: true } }
+							]
+						}
+					}
+				}
+			}
+		})
+	})
+
+	it("won't discriminate between possibly empty arrays", () => {
+		const t = type("string[]|boolean[]")
+		attest(t.raw.hasKind("union") && t.raw.discriminantJson).equals(null)
+	})
 })
diff --git a/ark/type/__tests__/divisor.test.ts b/ark/type/__tests__/divisor.test.ts
index a22dcd6233..2eb6f9e145 100644
--- a/ark/type/__tests__/divisor.test.ts
+++ b/ark/type/__tests__/divisor.test.ts
@@ -107,7 +107,7 @@ contextualize(
 
 		it("invalid literal", () => {
 			attest(() => type("number%3&8")).throws.snap(
-				"ParseError: Intersection of 8 and number & % 3 results in an unsatisfiable type"
+				"ParseError: Intersection of 8 and % 3 results in an unsatisfiable type"
 			)
 		})
 	}
diff --git a/ark/type/__tests__/expressions.test.ts b/ark/type/__tests__/expressions.test.ts
index 1bcf65ecf4..af89ade278 100644
--- a/ark/type/__tests__/expressions.test.ts
+++ b/ark/type/__tests__/expressions.test.ts
@@ -51,6 +51,7 @@ contextualize(
 					"email",
 					"uuid",
 					"semver",
+					"ip",
 					"Record",
 					"instanceof",
 					"===",
@@ -90,7 +91,6 @@ contextualize(
 					"keyof",
 					"parse",
 					"void",
-					"[]",
 					"url",
 					"alpha",
 					"alphanumeric",
@@ -100,7 +100,9 @@ contextualize(
 					"email",
 					"uuid",
 					"semver",
+					"ip",
 					"Record",
+					"[]",
 					"|",
 					":",
 					"=>",
diff --git a/ark/type/__tests__/keywords.test.ts b/ark/type/__tests__/keywords.test.ts
index ed4a0ecc4b..df4dcfd886 100644
--- a/ark/type/__tests__/keywords.test.ts
+++ b/ark/type/__tests__/keywords.test.ts
@@ -51,10 +51,6 @@ contextualize(
 			const expected = rawRoot([{ unit: false }, { unit: true }])
 			// should be simplified to simple checks for true and false literals
 			attest(boolean.json).equals(expected.json)
-			// TODO:
-			// 			attest(boolean.json).snap(`if( $arkRoot !== false && $arkRoot !== true) {
-			//     return false
-			// }`)
 		})
 
 		it("never", () => {
@@ -84,130 +80,143 @@ contextualize(
 			//should be treated as undefined at runtime
 			attest(t.json).equals(expected.json)
 		})
+	},
+	"validation",
+	() => {
+		it("integer", () => {
+			const integer = type("integer")
+			attest(integer(123)).equals(123)
+			attest(integer("123").toString()).snap("must be a number (was string)")
+			attest(integer(12.12).toString()).snap("must be an integer (was 12.12)")
+		})
+		it("alpha", () => {
+			const alpha = type("alpha")
+			attest(alpha("user")).snap("user")
+			attest(alpha("user123").toString()).equals(
+				'must be only letters (was "user123")'
+			)
+		})
+		it("alphanumeric", () => {
+			const alphanumeric = type("alphanumeric")
+			attest(alphanumeric("user123")).snap("user123")
+			attest(alphanumeric("user")).snap("user")
+			attest(alphanumeric("123")).snap("123")
+			attest(alphanumeric("abc@123").toString()).equals(
+				'must be only letters and digits (was "abc@123")'
+			)
+		})
+		it("lowercase", () => {
+			const lowercase = type("lowercase")
+			attest(lowercase("var")).snap("var")
+			attest(lowercase("newVar").toString()).equals(
+				'must be only lowercase letters (was "newVar")'
+			)
+		})
+		it("uppercase", () => {
+			const uppercase = type("uppercase")
+			attest(uppercase("VAR")).snap("VAR")
+			attest(uppercase("CONST_VAR").toString()).equals(
+				'must be only uppercase letters (was "CONST_VAR")'
+			)
+			attest(uppercase("myVar").toString()).equals(
+				'must be only uppercase letters (was "myVar")'
+			)
+		})
+		it("email", () => {
+			const email = type("email")
+			attest(email("shawn@mail.com")).snap("shawn@mail.com")
+			attest(email("shawn@email").toString()).equals(
+				'must be a valid email (was "shawn@email")'
+			)
+		})
+		it("uuid", () => {
+			const uuid = type("uuid")
+			attest(uuid("f70b8242-dd57-4e6b-b0b7-649d997140a0")).equals(
+				"f70b8242-dd57-4e6b-b0b7-649d997140a0"
+			)
+			attest(uuid("1234").toString()).equals(
+				'must be a valid UUID (was "1234")'
+			)
+		})
+
+		it("credit card", () => {
+			const validCC = "5489582921773376"
+			attest(ark.creditCard(validCC)).equals(validCC)
+			// Regex validation
+			attest(ark.creditCard("0".repeat(16)).toString()).equals(
+				'must be a valid credit card number (was "0000000000000000")'
+			)
+			// Luhn validation
+			attest(ark.creditCard(validCC.slice(0, -1) + "0").toString()).equals(
+				'must be a valid credit card number (was "5489582921773370")'
+			)
+		})
+		it("semver", () => {
+			attest(ark.semver("1.0.0")).snap("1.0.0")
+			attest(ark.semver("-1.0.0").toString()).equals(
+				'must be a valid semantic version (see https://semver.org/) (was "-1.0.0")'
+			)
+		})
+
+		it("ip", () => {
+			const ip = type("ip")
+
+			// valid IPv4 address
+			attest(ip("192.168.1.1")).snap("192.168.1.1")
+			// valid IPv6 address
+			attest(ip("2001:0db8:85a3:0000:0000:8a2e:0370:7334")).snap(
+				"2001:0db8:85a3:0000:0000:8a2e:0370:7334"
+			)
+
+			attest(ip("192.168.1.256").toString()).snap(
+				'must be a valid IPv4 address or a valid IPv6 address (was "192.168.1.256")'
+			)
+			attest(ip("2001:0db8:85a3:0000:0000:8a2e:0370:733g").toString()).snap(
+				'must be a valid IPv4 address or a valid IPv6 address (was "2001:0db8:85a3:0000:0000:8a2e:0370:733g")'
+			)
+		})
+	},
+	"parse",
+	() => {
+		it("json", () => {
+			const parseJson = type("parse.json")
+			attest(parseJson('{"a": "hello"}')).snap({ a: "hello" })
+			attest(parseJson(123).toString()).snap("must be a string (was number)")
+			attest(parseJson("foo").toString()).snap(
+				'must be a valid JSON string (was "foo")'
+			)
+		})
+		it("number", () => {
+			const parseNum = type("parse.number")
+			attest(parseNum("5")).equals(5)
+			attest(parseNum("5.5")).equals(5.5)
+			attest(parseNum("five").toString()).equals(
+				'must be a well-formed numeric string (was "five")'
+			)
+		})
+		it("integer", () => {
+			const parseInt = type("parse.integer")
+			attest(parseInt("5")).equals(5)
+			attest(parseInt("5.5").toString()).equals(
+				'must be a well-formed integer string (was "5.5")'
+			)
+			attest(parseInt("five").toString()).equals(
+				'must be a well-formed integer string (was "five")'
+			)
+			attest(parseInt(5).toString()).snap("must be a string (was number)")
+			attest(parseInt("9007199254740992").toString()).equals(
+				'must be an integer in the range Number.MIN_SAFE_INTEGER to Number.MAX_SAFE_INTEGER (was "9007199254740992")'
+			)
+		})
+		it("date", () => {
+			const parseDate = type("parse.date")
+			attest(parseDate("5/21/1993").toString()).snap(
+				"Fri May 21 1993 00:00:00 GMT-0400 (Eastern Daylight Time)"
+			)
+			attest(parseDate("foo").toString()).equals(
+				'must be a valid date (was "foo")'
+			)
+			attest(parseDate(5).toString()).snap("must be a string (was number)")
+		})
 	}
 )
-
-// describe("validation", () => {
-// it("integer", () => {
-//     const integer = type("integer")
-//     attest(integer(123)).equals(123)
-//     attest(integer("123").toString()).equals(
-//         "must be a number (was string)"
-//     )
-//     attest(integer(12.12).toString()).equals(
-//         "must be an integer (was 12.12)"
-//     )
-// })
-// it("alpha", () => {
-//     const alpha = type("alpha")
-//     attest(alpha("user")).equals("user")
-//     attest(alpha("user123").toString()).equals(
-//         "must be only letters (was 'user123')"
-//     )
-// })
-// it("alphanumeric", () => {
-//     const alphanumeric = type("alphanumeric")
-//     attest(alphanumeric("user123")).equals("user123")
-//     attest(alphanumeric("user")).equals("user")
-//     attest(alphanumeric("123")).equals("123")
-//     attest(alphanumeric("abc@123").toString()).equals(
-//         "must be only letters and digits (was 'abc@123')"
-//     )
-// })
-// it("lowercase", () => {
-//     const lowercase = type("lowercase")
-//     attest(lowercase("var")).equals("var")
-//     attest(lowercase("newVar").toString()).equals(
-//         "must be only lowercase letters (was 'newVar')"
-//     )
-// })
-// it("uppercase", () => {
-//     const uppercase = type("uppercase")
-//     attest(uppercase("VAR")).equals("VAR")
-//     attest(uppercase("CONST_VAR").toString()).equals(
-//         "must be only uppercase letters (was 'CONST_VAR')"
-//     )
-//     attest(uppercase("myVar").toString()).equals(
-//         "must be only uppercase letters (was 'myVar')"
-//     )
-// })
-// it("email", () => {
-//     const email = type("email")
-//     attest(email("shawn@mail.com")).equals("shawn@mail.com")
-//     attest(email("shawn@email").toString()).equals(
-//         "must be a valid email (was 'shawn@email')"
-//     )
-// })
-// it("uuid", () => {
-//     const uuid = type("uuid")
-//     attest(uuid("f70b8242-dd57-4e6b-b0b7-649d997140a0")).equals(
-//         "f70b8242-dd57-4e6b-b0b7-649d997140a0"
-//     )
-//     attest(uuid("1234").toString()).equals(
-//         "must be a valid UUID (was '1234')"
-//     )
-// })
-// it("parsedNumber", () => {
-//     const parsedNumber = type("parsedNumber")
-//     attest(parsedNumber("5")).equals(5)
-//     attest(parsedNumber("5.5")).equals(5.5)
-//     attest(parsedNumber("five").toString()).equals(
-//         "must be a well-formed numeric string (was 'five')"
-//     )
-// })
-// it("parsedInteger", () => {
-//     const parsedInteger = type("parsedInteger")
-//     attest(parsedInteger("5")).equals(5)
-//     attest(parsedInteger("5.5").toString()).equals(
-//         "must be a well-formed integer string (was '5.5')"
-//     )
-//     attest(parsedInteger("five").toString()).equals(
-//         "must be a well-formed integer string (was 'five')"
-//     )
-//     attest(parsedInteger(5).toString()).equals(
-//         "must be a string (was number)"
-//     )
-//     attest(parsedInteger("9007199254740992").toString()).equals(
-//         "must be an integer in the range Number.MIN_SAFE_INTEGER to Number.MAX_SAFE_INTEGER (was '9007199254740992')"
-//     )
-// })
-// it("parsedDate", () => {
-//     const parsedDate = type("parsedDate")
-//     attest(parsedDate("5/21/1993").out?.toDateString()).equals(
-//         "Fri May 21 1993"
-//     )
-//     attest(parsedDate("foo").toString()).equals(
-//         "must be a valid date (was 'foo')"
-//     )
-//     attest(parsedDate(5).toString()).equals(
-//         "must be a string (was number)"
-//     )
-// })
-// it("json", () => {
-//     const json = type("json")
-//     attest(json('{"a": "hello"}')).equals({ a: "hello" })
-//     attest(json(123).toString()).equals(
-//         "must be a JSON-parsable string (was number)"
-//     )
-// })
-// it("credit card", () => {
-//     const validCC = "5489582921773376"
-//     attest(ark.creditCard(validCC)).equals(validCC)
-//     // Regex validation
-//     attest(ark.creditCard("0".repeat(16)).toString()).equals(
-//         "must be a valid credit card number (was '0000000000000000')"
-//     )
-//     // Luhn validation
-//     attest(
-//         ark.creditCard(validCC.slice(0, -1) + "0").toString()
-//     ).equals(
-//         "must be a valid credit card number (was '5489582921773370')"
-//     )
-// })
-// it("semver", () => {
-//     attest(ark.semver("1.0.0")).equals("1.0.0")
-//     attest(ark.semver("-1.0.0").toString()).equals(
-//         "must be a valid semantic version (see https://semver.org/) (was '-1.0.0')"
-//     )
-// })
-// })
diff --git a/ark/type/__tests__/match.test.ts b/ark/type/__tests__/match.test.ts
index 6c179acb76..a9cb5471b4 100644
--- a/ark/type/__tests__/match.test.ts
+++ b/ark/type/__tests__/match.test.ts
@@ -3,9 +3,9 @@
 
 // it("cases only", () => {
 // 	const sizeOf = match({
-// 		"string|Array": (v) => v.length,
-// 		number: (v) => v,
-// 		bigint: (v) => v
+// 		"string|Array": v => v.length,
+// 		number: v => v,
+// 		bigint: v => v
 // 	}).orThrow()
 
 // 	attest<number>(sizeOf("abc")).equals(3)
@@ -14,8 +14,8 @@
 // })
 
 // it("properly infers types of inputs/outputs", () => {
-// 	const matcher = match({ string: (s) => s, number: (n) => n })
-// 		.when("boolean", (b) => b)
+// 	const matcher = match({ string: s => s, number: n => n })
+// 		.when("boolean", b => b)
 // 		.orThrow()
 
 // 	// properly infers the type of the output based on the input
@@ -28,19 +28,19 @@
 // })
 
 // it("`.when` errors on redundant cases", () => {
-// 	const matcher = match().when("string", (s) => s)
+// 	const matcher = match().when("string", s => s)
 
 // 	// @ts-expect-error
-// 	attest(() => matcher.when("string", (s) => s)).throwsAndHasTypeError(
+// 	attest(() => matcher.when("string", s => s)).throwsAndHasTypeError(
 // 		"This branch is redundant and will never be reached" // TODO: rewrite error message
 // 	)
 // })
 
 // it("errors on cases redundant to a previous `cases` block", () => {
-// 	const matcher = match({ string: (s) => s })
+// 	const matcher = match({ string: s => s })
 
 // 	// @ts-expect-error
-// 	attest(() => matcher.cases({ string: (s) => s })).throwsAndHasTypeError(
+// 	attest(() => matcher.cases({ string: s => s })).throwsAndHasTypeError(
 // 		"This branch is redundant and will never be reached"
 // 	)
 // })
@@ -64,7 +64,7 @@
 // describe('"finalizations"', () => {
 // 	it(".orThrow()", () => {
 // 		const matcher = match()
-// 			.when("string", (s) => s)
+// 			.when("string", s => s)
 // 			.orThrow()
 
 // 		// properly returns the `never` type and throws given a guaranteed-to-be-invalid input
@@ -108,7 +108,7 @@
 // 	// })
 
 // 	it("errors when attempting to `.finalize()` a non-exhaustive matcher", () => {
-// 		const matcher = match().when("string", (s) => s)
+// 		const matcher = match().when("string", s => s)
 
 // 		// @ts-expect-error
 // 		attest(() => matcher.finalize()).throwsAndHasTypeError(
@@ -118,7 +118,7 @@
 
 // 	it("considers `unknown` exhaustive", () => {
 // 		const matcher = match()
-// 			.when("unknown", (x) => x)
+// 			.when("unknown", x => x)
 // 			.finalize()
 
 // 		attest(matcher(4)).equals(4)
@@ -129,8 +129,8 @@
 // 	it("does not accept invalid inputs at a type-level", () => {
 // 		const matcher = match
 // 			.only<string | number>()
-// 			.when("string", (s) => s)
-// 			.when("number", (n) => n)
+// 			.when("string", s => s)
+// 			.when("number", n => n)
 // 			.finalize()
 
 // 		// @ts-expect-error
@@ -140,7 +140,7 @@
 // 	})
 
 // 	it("errors when attempting to `.finalize()` a non-exhaustive matcher", () => {
-// 		const matcher = match.only<string | number>().when("string", (s) => s)
+// 		const matcher = match.only<string | number>().when("string", s => s)
 
 // 		// @ts-expect-error
 // 		attest(() => matcher.finalize()).throwsAndHasTypeError(
@@ -148,11 +148,11 @@
 // 		)
 // 	})
 
-// 	it("allows finalizing exhaustive matchers", (_) => {
+// 	it("allows finalizing exhaustive matchers", _ => {
 // 		const matcher = match
 // 			.only<string | number>()
-// 			.when("string", (s) => s)
-// 			.when("number", (n) => n)
+// 			.when("string", s => s)
+// 			.when("number", n => n)
 // 			.finalize()
 
 // 		attest<string>(matcher("abc")).equals("abc")
@@ -164,8 +164,8 @@
 // 	it("infers the parameter to chained .default as the remaining cases", () => {
 // 		const matcher = match
 // 			.only<string | number | boolean>()
-// 			.when("string", (s) => s)
-// 			.default((n) => {
+// 			.when("string", s => s)
+// 			.default(n => {
 // 				attest<number | boolean>(n)
 // 				return n
 // 			})
@@ -176,8 +176,8 @@
 
 // 	it("infers the parameter to in-cases .default", () => {
 // 		const matcher = match.only<string | number | boolean>().cases({
-// 			string: (s) => s,
-// 			default: (n) => {
+// 			string: s => s,
+// 			default: n => {
 // 				// TS doesn't understand sequentiality in cases, so it's inferred as the in-type
 // 				attest<string | number | boolean>(n)
 // 				return n
@@ -191,7 +191,7 @@
 // 	it("returns `never` on only the specific cases handled by `.orThrow`", () => {
 // 		const matcher = match
 // 			.only<string | number>()
-// 			.when("string", (s) => s)
+// 			.when("string", s => s)
 // 			.orThrow()
 
 // 		attest<never>(matcher(4))
@@ -203,12 +203,12 @@
 
 // 	const matcher = threeSixtyNoScope
 // 		.match({
-// 			three: (three) => {
+// 			three: three => {
 // 				attest<3>(three)
 // 				return 3
 // 			}
 // 		})
-// 		.when("sixty", (sixty) => {
+// 		.when("sixty", sixty => {
 // 			attest<60>(sixty)
 // 			return 60
 // 		})
@@ -221,14 +221,14 @@
 
 // it("properly propagates errors from invalid type definitions in `when`", () => {
 // 	// @ts-expect-error
-// 	attest(() => match().when("strong", (s) => s)).type.errors(
+// 	attest(() => match().when("strong", s => s)).type.errors(
 // 		"'strong' is unresolvable"
 // 	)
 // })
 
 // it("properly propagates errors from invalid type definitions in `cases`", () => {
 // 	// @ts-expect-error
-// 	attest(() => match({ strong: (s) => s })).type.errors(
+// 	attest(() => match({ strong: s => s })).type.errors(
 // 		"'strong' is unresolvable"
 // 	)
 // })
diff --git a/ark/type/__tests__/pipe.test.ts b/ark/type/__tests__/pipe.test.ts
index 515b644fba..49c4212b0a 100644
--- a/ark/type/__tests__/pipe.test.ts
+++ b/ark/type/__tests__/pipe.test.ts
@@ -216,6 +216,7 @@ contextualize(() => {
 	it("union with output", () => {
 		const t = type("number|parse.number")
 		attest<number>(t.infer)
+		attest<string | number>(t.inferIn)
 	})
 
 	it("deep union", () => {
diff --git a/ark/type/__tests__/realWorld.test.ts b/ark/type/__tests__/realWorld.test.ts
index 77019a6c7a..ea5ba55b3e 100644
--- a/ark/type/__tests__/realWorld.test.ts
+++ b/ark/type/__tests__/realWorld.test.ts
@@ -1,4 +1,6 @@
 import { attest, contextualize } from "@arktype/attest"
+import type { AtLeastLength, AtMostLength, Out, string } from "@arktype/schema"
+import { registeredReference } from "@arktype/util"
 import { scope, type, type Type } from "arktype"
 
 contextualize(() => {
@@ -246,4 +248,120 @@ nospace must be matched by ^\\S*$ (was "One space")`)
 			]
 		})
 	})
+
+	// https://github.com/arktypeio/arktype/issues/947
+	it("chained inline type expression inference", () => {
+		const a = type({
+			action: "'a' | 'b'"
+		}).or({
+			action: "'c'"
+		})
+
+		const referenced = type({
+			someField: "string"
+		}).and(a)
+
+		attest<
+			| {
+					someField: string
+					action: "a" | "b"
+			  }
+			| {
+					someField: string
+					action: "c"
+			  }
+		>(referenced.infer)
+
+		const inlined = type({
+			someField: "string"
+		}).and(
+			type({
+				action: "'a' | 'b'"
+			}).or({
+				action: "'c'"
+			})
+		)
+
+		attest<typeof referenced>(inlined)
+	})
+
+	// https://discord.com/channels/957797212103016458/1242116299547476100
+	it("infers morphs at nested paths", () => {
+		const parseBigint = type("string", "=>", (s, ctx) => {
+			try {
+				return BigInt(s)
+			} catch {
+				return ctx.error("a valid number")
+			}
+		})
+
+		const Test = type({
+			group: {
+				nested: {
+					value: parseBigint
+				}
+			}
+		})
+
+		const out = Test({ group: { nested: { value: "5" } } })
+		attest<bigint, typeof Test.infer.group.nested.value>()
+		attest(out).equals({ group: { nested: { value: 5n } } })
+	})
+
+	// https://discord.com/channels/957797212103016458/957804102685982740/1242221022380556400
+	it("nested pipe to validated output", () => {
+		const trimString = (s: string) => s.trim()
+
+		const trimStringReference = registeredReference(trimString)
+
+		const validatedTrimString = type("string").pipe(
+			trimString,
+			type("1<=string<=3")
+		)
+
+		const CreatePatientInput = type({
+			"patient_id?": "string|null",
+			"first_name?": validatedTrimString.or("null"),
+			"middle_name?": "string|null",
+			"last_name?": "string|null"
+		})
+
+		attest<
+			| ((In: string) => Out<string.is<AtLeastLength<1> & AtMostLength<3>>>)
+			| null
+			| undefined,
+			typeof CreatePatientInput.t.first_name
+		>()
+
+		attest(CreatePatientInput.json).snap({
+			optional: [
+				{
+					key: "first_name",
+					value: [
+						{
+							in: "string",
+							morphs: [
+								trimStringReference,
+								{ domain: "string", maxLength: 3, minLength: 1 }
+							]
+						},
+						{ unit: null }
+					]
+				},
+				{ key: "last_name", value: ["string", { unit: null }] },
+				{ key: "middle_name", value: ["string", { unit: null }] },
+				{ key: "patient_id", value: ["string", { unit: null }] }
+			],
+			domain: "object"
+		})
+		attest(CreatePatientInput({ first_name: " Bob  " })).equals({
+			first_name: "Bob"
+		})
+		attest(CreatePatientInput({ first_name: " John  " }).toString()).snap(
+			"first_name must be at most length 3 (was 4)"
+		)
+		attest(CreatePatientInput({ first_name: 5 }).toString()).snap(
+			"first_name must be a string or null (was 5)"
+		)
+	})
 })
diff --git a/ark/type/__tests__/scope.test.ts b/ark/type/__tests__/scope.test.ts
index 5f7659ba0b..7fc10fdcf2 100644
--- a/ark/type/__tests__/scope.test.ts
+++ b/ark/type/__tests__/scope.test.ts
@@ -313,7 +313,7 @@ dependencies[1].contributors[0].email must be a valid email (was "ssalbdivad")`)
 			attest(types.a(valid)).equals(valid)
 
 			attest(types.a({ b: { a: { b: { a: 4 } } } }).toString()).snap(
-				'b.a.b.a must be an object or 3 (was number, 4) or b.a must be 3 (was {"b":{"a":4}})'
+				'b.a.b.a must be an object or 3 (was 4) or b.a must be 3 (was {"b":{"a":4}})'
 			)
 
 			attest(types.b.infer).type.toString.snap("{ a: 3 | { b: ...; }; }")
diff --git a/ark/type/__tests__/traverse.test.ts b/ark/type/__tests__/traverse.test.ts
index d61334a834..1447080704 100644
--- a/ark/type/__tests__/traverse.test.ts
+++ b/ark/type/__tests__/traverse.test.ts
@@ -60,7 +60,8 @@ contextualize(() => {
 		const t = type("string|number[]")
 		attest(t([1])).snap([1])
 		attest(t("hello")).snap("hello")
-		attest(t(2).toString()).snap("must be a string or an array (was number)")
+		attest(t(2).toString()).snap("must be a string or an object (was number)")
+		attest(t({}).toString()).snap("must be an array (was object)")
 	})
 
 	it("tuple length", () => {
@@ -84,6 +85,13 @@ contextualize(() => {
 		)
 	})
 
+	it("common errors collapse", () => {
+		const t = type({ base: "1", a: "1" }, "|", { base: "1", b: "1" })
+		attest(t({ base: 1, a: 1 })).snap({ base: 1, a: 1 })
+		attest(t({ base: 1, b: 1 })).snap({ base: 1, b: 1 })
+		attest(t({ a: 1, b: 1 }).toString()).snap("base must be 1 (was missing)")
+	})
+
 	it("branches at path", () => {
 		const t = type({ key: [{ a: "string" }, "|", { b: "boolean" }] })
 		attest(t({ key: { a: "ok" } })).snap({ key: { a: "ok" } })
@@ -98,29 +106,28 @@ contextualize(() => {
 		attest(t({ a: "ok" })).snap({ a: "ok" })
 		attest(t({ a: 5 })).snap({ a: 5 })
 		// value isn't present
-		attest(t({}).toString()).snap(
-			"a must be a number, a string or null (was missing)"
-		)
+		attest(t({}).toString()).snap("a must be null (was missing)")
 		// unsatisfying value
-		attest(t({ a: false }).toString()).snap(
-			"a must be a number, a string or null (was false)"
-		)
+		attest(t({ a: false }).toString()).snap("a must be null (was false)")
 	})
 
-	it("multiple switch", () => {
-		const types = scope({
-			a: { foo: "string" },
-			b: { foo: "number" },
-			c: { foo: "Function" },
-			d: "a|b|c"
-		}).export()
-		attest(types.d({}).toString()).snap(
-			"foo must be a function, a number or a string (was missing)"
-		)
-		attest(types.d({ foo: null }).toString()).snap(
-			"foo must be a function, a number or a string (was null)"
-		)
-	})
+	// TODO: https://github.com/arktypeio/arktype/issues/962
+	// it("multiple switch", () => {
+	// 	const types = scope({
+	// 		a: { foo: "string" },
+	// 		b: { foo: "number" },
+	// 		c: { foo: "Function" },
+	// 		d: "a|b|c"
+	// 	}).export()
+	// 	// attest(types.d({}).toString()).snap(
+	// 	// 	"foo must be a number, an object or a string (was undefined)"
+	// 	// )
+	// 	// this could be improved, currently a bit counterintuitive because of
+	// 	// the inconsistency between `domainOf` and typeof
+	// 	attest(types.d({ foo: null }).toString()).snap(
+	// 		"foo must be a function (was null)"
+	// 	)
+	// })
 
 	it("multi", () => {
 		const naturalNumber = type("integer>0")
diff --git a/ark/type/__tests__/undeclaredKeys.test.ts b/ark/type/__tests__/undeclaredKeys.test.ts
index 843ae1da6f..b19eb84c6f 100644
--- a/ark/type/__tests__/undeclaredKeys.test.ts
+++ b/ark/type/__tests__/undeclaredKeys.test.ts
@@ -59,7 +59,7 @@ b must be removed`)
 			"reject"
 		)
 		attest(o({ a: 2, b: true }).toString()).snap(
-			"a must be a string or removed (was number)"
+			"a must be a string or removed (was 2)"
 		)
 	})
 })
diff --git a/ark/type/__tests__/union.test.ts b/ark/type/__tests__/union.test.ts
index f760431169..27559d325a 100644
--- a/ark/type/__tests__/union.test.ts
+++ b/ark/type/__tests__/union.test.ts
@@ -36,7 +36,7 @@ contextualize(() => {
 		attest(t.json).equals(expected.json)
 	})
 
-	it("union of true and false reduces to boolean", () => {
+	it("boolean is a union of true | false", () => {
 		const t = type("true|false")
 		attest(t.infer).type.toString("boolean")
 		attest(t.json).equals(type("boolean").json)
@@ -106,6 +106,55 @@ contextualize(() => {
 				| 44
 				| 45
 			>(t.infer)
+
+		attest(t.json).snap([
+			{ unit: 0 },
+			{ unit: 10 },
+			{ unit: 11 },
+			{ unit: 12 },
+			{ unit: 13 },
+			{ unit: 14 },
+			{ unit: 15 },
+			{ unit: 16 },
+			{ unit: 17 },
+			{ unit: 18 },
+			{ unit: 19 },
+			{ unit: 1 },
+			{ unit: 20 },
+			{ unit: 21 },
+			{ unit: 22 },
+			{ unit: 23 },
+			{ unit: 24 },
+			{ unit: 25 },
+			{ unit: 26 },
+			{ unit: 27 },
+			{ unit: 28 },
+			{ unit: 29 },
+			{ unit: 2 },
+			{ unit: 30 },
+			{ unit: 31 },
+			{ unit: 32 },
+			{ unit: 33 },
+			{ unit: 34 },
+			{ unit: 35 },
+			{ unit: 36 },
+			{ unit: 37 },
+			{ unit: 38 },
+			{ unit: 39 },
+			{ unit: 3 },
+			{ unit: 40 },
+			{ unit: 41 },
+			{ unit: 42 },
+			{ unit: 43 },
+			{ unit: 44 },
+			{ unit: 45 },
+			{ unit: 4 },
+			{ unit: 5 },
+			{ unit: 6 },
+			{ unit: 7 },
+			{ unit: 8 },
+			{ unit: 9 }
+		])
 	})
 
 	const expected = () =>
diff --git a/ark/type/api.ts b/ark/type/api.ts
index ca01717f62..295759fdb7 100644
--- a/ark/type/api.ts
+++ b/ark/type/api.ts
@@ -1,4 +1,4 @@
-export { ArkError as ArkError, ArkErrors } from "@arktype/schema"
+export { ArkError, ArkErrors } from "@arktype/schema"
 export type { Ark, ArkConfig, Out } from "@arktype/schema"
 export { ambient, ark, declare, define, match, type } from "./ark.js"
 export { Module } from "./module.js"
diff --git a/ark/type/generic.ts b/ark/type/generic.ts
index 4a47fad1e3..8ee1561864 100644
--- a/ark/type/generic.ts
+++ b/ark/type/generic.ts
@@ -1,8 +1,8 @@
 import {
+	arkKind,
 	type GenericNodeInstantiation,
 	type GenericProps,
-	type RootScope,
-	arkKind
+	type RootScope
 } from "@arktype/schema"
 import { Callable, type conform } from "@arktype/util"
 import type { inferDefinition } from "./parser/definition.js"
@@ -11,6 +11,7 @@ import type {
 	parseGenericParams
 } from "./parser/generic.js"
 import type { Type, inferTypeRoot, validateTypeRoot } from "./type.js"
+
 export type validateParameterString<params extends string> =
 	parseGenericParams<params> extends GenericParamsParseError<infer message> ?
 		message
diff --git a/ark/type/match.ts b/ark/type/match.ts
index f6f2f3df77..8eb34da3f6 100644
--- a/ark/type/match.ts
+++ b/ark/type/match.ts
@@ -156,63 +156,63 @@ export type MatchInvocation<ctx extends MatchInvocationContext> = <
 	:	ReturnType<ctx["thens"][i]>
 }[numericStringKeyOf<ctx["thens"]>]
 
-export const createMatchParser = <$>($: Scope): MatchParser<$> => {
-	return (() => {}).bind($) as never
-	// const matchParser = (isRestricted: boolean) => {
-	// 	const handledCases: { when: RawRoot; then: Morph }[] = []
-	// 	let defaultCase: ((x: unknown) => unknown) | null = null
-
-	// 	const parser = {
-	// 		when: (when: unknown, then: Morph) => {
-	// 			handledCases.push({ when: $.parseRoot(when, {}), then })
-
-	// 			return parser
-	// 		},
-
-	// 		finalize: () => {
-	// 			// TODO: exhaustiveness checking
-	// 			const branches = handledCases.flatMap(({ when, then }) => {
-	// 				if (when.kind === "union") {
-	// 					return when.branches.map((branch) => ({
-	// 						in: branch,
-	// 						morph: then
-	// 					}))
-	// 				}
-	// 				if (when.kind === "morph") {
-	// 					return [{ in: when, morph: [when.morph, then] }]
-	// 				}
-	// 				return [{ in: when, morph: then }]
-	// 			})
-	// 			if (defaultCase) {
-	// 				branches.push({ in: keywordNodes.unknown, morph: defaultCase })
-	// 			}
-	// 			const matchers = $.node("union", {
-	// 				branches,
-	// 				ordered: true
-	// 			})
-	// 			return matchers.assert
-	// 		},
-
-	// 		orThrow: () => {
-	// 			// implicitly finalize, we don't need to do anything else because we throw either way
-	// 			return parser.finalize()
-	// 		},
-
-	// 		default: (x: unknown) => {
-	// 			if (x instanceof Function) {
-	// 				defaultCase = x as never
-	// 			} else {
-	// 				defaultCase = () => x
-	// 			}
-
-	// 			return parser.finalize()
-	// 		}
-	// 	}
-
-	// 	return parser
-	// }
-
-	// return Object.assign(() => matchParser(false), {
-	// 	only: () => matchParser(true)
-	// }) as never
-}
+export const createMatchParser = <$>($: Scope): MatchParser<$> =>
+	(() => {}).bind($) as never
+
+// const matchParser = (isRestricted: boolean) => {
+// 	const handledCases: { when: RawRoot; then: Morph }[] = []
+// 	let defaultCase: ((x: unknown) => unknown) | null = null
+
+// 	const parser = {
+// 		when: (when: unknown, then: Morph) => {
+// 			handledCases.push({ when: $.parseRoot(when, {}), then })
+
+// 			return parser
+// 		},
+
+// 		finalize: () => {
+// 			// TODO: exhaustiveness checking
+// 			const branches = handledCases.flatMap(({ when, then }) => {
+// 				if (when.kind === "union") {
+// 					return when.branches.map((branch) => ({
+// 						in: branch,
+// 						morph: then
+// 					}))
+// 				}
+// 				if (when.kind === "morph") {
+// 					return [{ in: when, morph: [when.morph, then] }]
+// 				}
+// 				return [{ in: when, morph: then }]
+// 			})
+// 			if (defaultCase) {
+// 				branches.push({ in: keywordNodes.unknown, morph: defaultCase })
+// 			}
+// 			const matchers = $.node("union", {
+// 				branches,
+// 				ordered: true
+// 			})
+// 			return matchers.assert
+// 		},
+
+// 		orThrow: () => {
+// 			// implicitly finalize, we don't need to do anything else because we throw either way
+// 			return parser.finalize()
+// 		},
+
+// 		default: (x: unknown) => {
+// 			if (x instanceof Function) {
+// 				defaultCase = x as never
+// 			} else {
+// 				defaultCase = () => x
+// 			}
+
+// 			return parser.finalize()
+// 		}
+// 	}
+
+// 	return parser
+// }
+
+// return Object.assign(() => matchParser(false), {
+// 	only: () => matchParser(true)
+// }) as never
diff --git a/ark/type/package.json b/ark/type/package.json
index a06e1e1ee7..b58468ea5f 100644
--- a/ark/type/package.json
+++ b/ark/type/package.json
@@ -20,9 +20,6 @@
 		"./config": "./out/config.js",
 		"./internal/*": "./out/*"
 	},
-	"imports": {
-		"#foo": "../schema/api.ts"
-	},
 	"files": [
 		"out"
 	],
diff --git a/ark/type/parser/definition.ts b/ark/type/parser/definition.ts
index 34948ee31a..c3ab2c7a0b 100644
--- a/ark/type/parser/definition.ts
+++ b/ark/type/parser/definition.ts
@@ -63,7 +63,10 @@ export const parseObject = (def: object, ctx: ParseContext): BaseRoot => {
 }
 
 export type inferDefinition<def, $, args> =
-	[def] extends [anyOrNever] ? def
+	[def] extends [anyOrNever] ?
+		def extends never ?
+			never
+		:	any
 	: def extends type.cast<infer t> | ThunkCast<infer t> ? t
 	: def extends string ? inferString<def, $, args>
 	: def extends array ? inferTuple<def, $, args>
diff --git a/ark/type/parser/string/shift/operand/operand.ts b/ark/type/parser/string/shift/operand/operand.ts
index 19b19720b9..97b076ca12 100644
--- a/ark/type/parser/string/shift/operand/operand.ts
+++ b/ark/type/parser/string/shift/operand/operand.ts
@@ -3,10 +3,11 @@ import type { StaticState, state } from "../../reduce/static.js"
 import type { BaseCompletions } from "../../string.js"
 import { Scanner } from "../scanner.js"
 import {
-	type EnclosingQuote,
-	type EnclosingStartToken,
 	enclosingChar,
-	parseEnclosed
+	enclosingQuote,
+	parseEnclosed,
+	type EnclosingQuote,
+	type EnclosingStartToken
 } from "./enclosed.js"
 import { parseUnenclosed, writeMissingOperandMessage } from "./unenclosed.js"
 
@@ -17,8 +18,11 @@ export const parseOperand = (s: DynamicState): void =>
 	: s.scanner.lookaheadIsIn(Scanner.whiteSpaceTokens) ?
 		parseOperand(s.shiftedByOne())
 	: s.scanner.lookahead === "d" ?
-		s.shiftedByOne().scanner.lookaheadIsIn(enclosingChar) ?
-			parseEnclosed(s, `d${s.scanner.shift()}` as EnclosingStartToken)
+		s.scanner.nextLookahead in enclosingQuote ?
+			parseEnclosed(
+				s,
+				`${s.scanner.shift()}${s.scanner.shift()}` as EnclosingStartToken
+			)
 		:	parseUnenclosed(s)
 	:	parseUnenclosed(s)
 
diff --git a/ark/type/parser/string/shift/scanner.ts b/ark/type/parser/string/shift/scanner.ts
index b0f7d72957..c9ead3e15d 100644
--- a/ark/type/parser/string/shift/scanner.ts
+++ b/ark/type/parser/string/shift/scanner.ts
@@ -1,7 +1,7 @@
-import { type Dict, isKeyOf } from "@arktype/util"
+import { isKeyOf, type Dict } from "@arktype/util"
 import type { Comparator } from "../reduce/shared.js"
 
-export class Scanner<Lookahead extends string = string> {
+export class Scanner<lookahead extends string = string> {
 	private chars: string[]
 	private i: number
 
@@ -11,12 +11,16 @@ export class Scanner<Lookahead extends string = string> {
 	}
 
 	/** Get lookahead and advance scanner by one */
-	shift(): Lookahead {
-		return (this.chars[this.i++] ?? "") as Lookahead
+	shift(): lookahead {
+		return (this.chars[this.i++] ?? "") as never
 	}
 
-	get lookahead(): Lookahead {
-		return (this.chars[this.i] ?? "") as Lookahead
+	get lookahead(): lookahead {
+		return (this.chars[this.i] ?? "") as never
+	}
+
+	get nextLookahead(): string {
+		return this.chars[this.i + 1] ?? ""
 	}
 
 	get length(): number {
@@ -65,13 +69,13 @@ export class Scanner<Lookahead extends string = string> {
 		return this.chars.slice(start, end).join("")
 	}
 
-	lookaheadIs<Char extends Lookahead>(char: Char): this is Scanner<Char> {
+	lookaheadIs<char extends lookahead>(char: char): this is Scanner<char> {
 		return this.lookahead === char
 	}
 
-	lookaheadIsIn<Tokens extends Dict>(
-		tokens: Tokens
-	): this is Scanner<Extract<keyof Tokens, string>> {
+	lookaheadIsIn<tokens extends Dict>(
+		tokens: tokens
+	): this is Scanner<Extract<keyof tokens, string>> {
 		return this.lookahead in tokens
 	}
 }
diff --git a/ark/type/scope.ts b/ark/type/scope.ts
index 1271cc39f9..17205038d7 100644
--- a/ark/type/scope.ts
+++ b/ark/type/scope.ts
@@ -27,7 +27,6 @@ import {
 	type nominal,
 	type show
 } from "@arktype/util"
-import type { type } from "./ark.js"
 import { Generic } from "./generic.js"
 import { createMatchParser, type MatchParser } from "./match.js"
 import type { Module } from "./module.js"
@@ -146,9 +145,7 @@ export type moduleKeyOf<$> = {
 export type tryInferSubmoduleReference<$, token> =
 	token extends `${infer submodule extends moduleKeyOf<$>}.${infer subalias}` ?
 		subalias extends keyof $[submodule] ?
-			$[submodule][subalias] extends type.cast<infer t> ?
-				t
-			:	never
+			$[submodule][subalias]
 		:	never
 	:	never
 
diff --git a/ark/util/__tests__/hkt.test.ts b/ark/util/__tests__/hkt.test.ts
index ed5590b1bf..dd152fa04c 100644
--- a/ark/util/__tests__/hkt.test.ts
+++ b/ark/util/__tests__/hkt.test.ts
@@ -57,9 +57,8 @@ contextualize(() => {
 		const AddD = new (class AddD extends Hkt.UnaryKind {
 			hkt = (
 				args: conform<this[Hkt.args], { c: number }>
-			): show<typeof args & { d: (typeof args)["c"] }> => {
-				return Object.assign(args, { d: args.c } as const)
-			}
+			): show<typeof args & { d: (typeof args)["c"] }> =>
+				Object.assign(args, { d: args.c } as const)
 		})()
 		// @ts-expect-error
 		attest(() => Hkt.pipe(AddB, AddD)).type.errors.snap(
diff --git a/ark/util/arrays.ts b/ark/util/arrays.ts
index cb7c0f0aba..7006eda2bc 100644
--- a/ark/util/arrays.ts
+++ b/ark/util/arrays.ts
@@ -229,20 +229,20 @@ export type groupableKeyOf<t> = {
 	[k in keyof t]: t[k] extends PropertyKey ? k : never
 }[keyof t]
 
-export type groupBy<element, discriminator extends groupableKeyOf<element>> = {
-	[k in element[discriminator] & PropertyKey]?: (element extends unknown ?
-		isDisjoint<element[discriminator], k> extends true ?
+export type groupBy<element, discriminant extends groupableKeyOf<element>> = {
+	[k in element[discriminant] & PropertyKey]?: (element extends unknown ?
+		isDisjoint<element[discriminant], k> extends true ?
 			never
 		:	element
 	:	never)[]
 } & unknown
 
-export const groupBy = <element, discriminator extends groupableKeyOf<element>>(
+export const groupBy = <element, discriminant extends groupableKeyOf<element>>(
 	array: readonly element[],
-	discriminator: discriminator
-): groupBy<element, discriminator> =>
+	discriminant: discriminant
+): groupBy<element, discriminant> =>
 	array.reduce<Record<PropertyKey, any>>((result, item) => {
-		const key = item[discriminator] as never
+		const key = item[discriminant] as never
 		result[key] ??= []
 		result[key].push(item)
 		return result
diff --git a/ark/util/functions.ts b/ark/util/functions.ts
index d17244c891..a68f45b1c6 100644
--- a/ark/util/functions.ts
+++ b/ark/util/functions.ts
@@ -1,5 +1,5 @@
 import { throwInternalError } from "./errors.js"
-import { NoopBase } from "./records.js"
+import { NoopBase, unset } from "./records.js"
 
 export const bound = (
 	target: Function,
@@ -31,6 +31,11 @@ export const cached = <self>(
 		return value
 	}
 
+export const cachedThunk = <t>(thunk: () => t): (() => t) => {
+	let result: t | unset = unset
+	return () => (result === unset ? (result = thunk()) : result)
+}
+
 export const isThunk = <value>(
 	value: value
 ): value is Extract<value, Thunk> extends never ? value & Thunk
@@ -40,6 +45,17 @@ export type Thunk<ret = unknown> = () => ret
 
 export type thunkable<t> = t | Thunk<t>
 
+export const tryCatch = <returns, onError = never>(
+	fn: () => returns,
+	onError?: (e: unknown) => onError
+): returns | onError => {
+	try {
+		return fn()
+	} catch (e) {
+		return onError?.(e) as onError
+	}
+}
+
 export const DynamicFunction = class extends Function {
 	constructor(...args: [string, ...string[]]) {
 		const params = args.slice(0, -1)
@@ -91,3 +107,20 @@ export class Callable<
 export type Guardable<input = unknown, narrowed extends input = input> =
 	| ((In: input) => In is narrowed)
 	| ((In: input) => boolean)
+
+/**
+ * Checks if the environment has Content Security Policy (CSP) enabled,
+ * preventing JIT-optimized code from being compiled via new Function().
+ *
+ * @returns `true` if a function created using new Function() can be
+ * successfully invoked in the environment, `false` otherwise.
+ *
+ * The result is cached for subsequent invocations.
+ */
+export const envHasCsp = cachedThunk((): boolean => {
+	try {
+		return new Function("return false")()
+	} catch (e) {
+		return true
+	}
+})
diff --git a/ark/util/registry.ts b/ark/util/registry.ts
index 39299d5ff9..de7e1328dc 100644
--- a/ark/util/registry.ts
+++ b/ark/util/registry.ts
@@ -39,11 +39,10 @@ export type RegisteredReference<to extends string = string> = `$ark.${to}`
 export const isDotAccessible = (keyName: string): boolean =>
 	/^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(keyName)
 
-export const compileSerializedValue = (value: unknown): string => {
-	return hasDomain(value, "object") || typeof value === "symbol" ?
-			registeredReference(value)
-		:	serializePrimitive(value as SerializablePrimitive)
-}
+export const compileSerializedValue = (value: unknown): string =>
+	hasDomain(value, "object") || typeof value === "symbol" ?
+		registeredReference(value)
+	:	serializePrimitive(value as SerializablePrimitive)
 
 const baseNameFor = (value: object | symbol) => {
 	switch (typeof value) {
diff --git a/package.json b/package.json
index 6354fbcb9e..ca1b4bf302 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
 	},
 	"pnpm": {
 		"overrides": {
-			"esbuild": "0.21.2"
+			"esbuild": "0.21.3"
 		}
 	},
 	"mocha": {