Repository: JoshuaKGoldberg/bingo (ts)

Issue:
🐛 Bug: Stratum templates should have access to options.prefix: string
### Bug Report Checklist

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have pulled the latest `main` branch of the repository.
- [x] I have [searched for related issues](https://github.com/JoshuaKGoldberg/bingo/issues?q=is%3Aissue) and found none that matched my issue.

### Expected

All Stratum Templates have a `prefix` option automatically added. Blocks should therefore also have visibility into which preset is being run. This can be useful for, say, README.md blocks describing the block.

### Actual

No such `options.prefix` is available to Stratum Blocks right now.

### Additional Info

💝 

Pull request:
fix(bingo-stratum): allow Blocks to access options.preset
## PR Checklist

- [x] Addresses an existing open issue: fixes #269
- [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/bingo/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/bingo/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

Mostly a documentation and types update. Also extracts out `createBlock` to make it easier to find - similar to `createPreset` and `createTemplate`.

💝 

Patch:
diff --git a/packages/bingo-stratum/src/creators/createBase.ts b/packages/bingo-stratum/src/creators/createBase.ts
index b8a1313..2876f5c 100644
--- a/packages/bingo-stratum/src/creators/createBase.ts
+++ b/packages/bingo-stratum/src/creators/createBase.ts
@@ -1,17 +1,10 @@
-import { AnyOptionalShape, AnyShape, InferredObject } from "bingo";
+import { AnyShape } from "bingo";
 
 import { Base, BaseDefinition } from "../types/bases.js";
-import {
-	BlockContextWithAddons,
-	BlockDefinitionWithAddons,
-	BlockDefinitionWithoutAddons,
-	BlockWithAddons,
-	BlockWithoutAddons,
-} from "../types/blocks.js";
 import { assertNoPresetOption } from "./assertNoPresetOption.js";
+import { createBlock } from "./createBlock.js";
 import { createPreset } from "./createPreset.js";
 import { createStratumTemplate } from "./createStratumTemplate.js";
-import { applyZodDefaults, isDefinitionWithAddons } from "./utils.js";
 
 /**
  * Creates a Stratum {@link Base}.
@@ -21,48 +14,8 @@ import { applyZodDefaults, isDefinitionWithAddons } from "./utils.js";
 export function createBase<OptionsShape extends AnyShape>(
 	baseDefinition: BaseDefinition<OptionsShape>,
 ): Base<OptionsShape> {
-	type Options = InferredObject<OptionsShape>;
-
 	assertNoPresetOption(baseDefinition);
 
-	function createBlock<AddonsShape extends AnyOptionalShape>(
-		blockDefinition: BlockDefinitionWithAddons<AddonsShape, Options>,
-	): BlockWithAddons<InferredObject<AddonsShape>, Options>;
-	function createBlock(
-		blockDefinition: BlockDefinitionWithoutAddons<Options>,
-	): BlockWithoutAddons<Options>;
-	function createBlock<AddonsShape extends AnyOptionalShape>(
-		blockDefinition:
-			| BlockDefinitionWithAddons<AddonsShape, Options>
-			| BlockDefinitionWithoutAddons<Options>,
-	) {
-		// Blocks without Addons can't be called as functions.
-		if (!isDefinitionWithAddons(blockDefinition)) {
-			return blockDefinition;
-		}
-
-		const addonsSchema = blockDefinition.addons;
-
-		type Addons = InferredObject<AddonsShape>;
-
-		// Blocks with Addons do need to be callable as functions...
-		function block(addons: Addons) {
-			return { addons, block };
-		}
-
-		// ...and also still have the Block Definition properties.
-		Object.assign(block, blockDefinition);
-
-		block.produce = (context: BlockContextWithAddons<Addons, Options>) => {
-			return blockDefinition.produce({
-				...context,
-				addons: applyZodDefaults(addonsSchema, context.addons),
-			});
-		};
-
-		return block as BlockWithAddons<Addons, Options>;
-	}
-
 	const base: Base<OptionsShape> = {
 		...baseDefinition,
 		createBlock,
diff --git a/packages/bingo-stratum/src/creators/createBlock.ts b/packages/bingo-stratum/src/creators/createBlock.ts
new file mode 100644
index 0000000..bc4352d
--- /dev/null
+++ b/packages/bingo-stratum/src/creators/createBlock.ts
@@ -0,0 +1,54 @@
+import { AnyOptionalShape, InferredObject } from "bingo";
+
+import {
+	BlockContextWithAddons,
+	BlockDefinitionWithAddons,
+	BlockDefinitionWithoutAddons,
+	BlockWithAddons,
+	BlockWithoutAddons,
+} from "../types/blocks.js";
+import { applyZodDefaults, isDefinitionWithAddons } from "./utils.js";
+
+export function createBlock<
+	AddonsShape extends AnyOptionalShape,
+	Options extends object,
+>(
+	blockDefinition: BlockDefinitionWithAddons<AddonsShape, Options>,
+): BlockWithAddons<InferredObject<AddonsShape>, Options>;
+export function createBlock<Options extends object>(
+	blockDefinition: BlockDefinitionWithoutAddons<Options>,
+): BlockWithoutAddons<Options>;
+export function createBlock<
+	AddonsShape extends AnyOptionalShape,
+	Options extends object,
+>(
+	blockDefinition:
+		| BlockDefinitionWithAddons<AddonsShape, Options>
+		| BlockDefinitionWithoutAddons<Options>,
+) {
+	// Blocks without Addons can't be called as functions.
+	if (!isDefinitionWithAddons(blockDefinition)) {
+		return blockDefinition;
+	}
+
+	const addonsSchema = blockDefinition.addons;
+
+	type Addons = InferredObject<AddonsShape>;
+
+	// Blocks with Addons do need to be callable as functions...
+	function block(addons: Addons) {
+		return { addons, block };
+	}
+
+	// ...and also still have the Block Definition properties.
+	Object.assign(block, blockDefinition);
+
+	block.produce = (context: BlockContextWithAddons<Addons, Options>) => {
+		return blockDefinition.produce({
+			...context,
+			addons: applyZodDefaults(addonsSchema, context.addons),
+		});
+	};
+
+	return block as BlockWithAddons<Addons, Options>;
+}
diff --git a/packages/bingo-stratum/src/producers/produceBlock.ts b/packages/bingo-stratum/src/producers/produceBlock.ts
index d182547..e6f66ea 100644
--- a/packages/bingo-stratum/src/producers/produceBlock.ts
+++ b/packages/bingo-stratum/src/producers/produceBlock.ts
@@ -3,11 +3,12 @@ import { ProductionMode } from "bingo";
 import { mergeBlockCreations } from "../mergers/mergeBlockCreations.js";
 import { BlockWithAddons, BlockWithoutAddons } from "../types/blocks.js";
 import { BlockCreation } from "../types/creations.js";
+import { StratumTemplateOptions } from "../types/templates.js";
 
 /**
  * Settings to run a Block with {@link produceBlock} that might have addons.
  * @template Addons Schema of Block-specific args defined by the Block, if defined.
- * @template Options Options values as described by the Block's Base's options schema.
+ * @template Options Options values as described by the Block's Base's options schema, as well as preset.
  * @see {@link https://www.create.bingo/engines/stratum/apis/producers#produceblock}
  */
 export type ProduceBlockSettings<
@@ -20,7 +21,7 @@ export type ProduceBlockSettings<
 /**
  * Settings to run a Block with {@link produceBlock} that defines addons.
  * @template Addons Schema of Block-specific args defined by the Block.
- * @template Options Options values as described by the Block's Base's options schema.
+ * @template Options Options values as described by the Block's Base's options schema, as well as preset.
  * @see {@link https://www.create.bingo/engines/stratum/apis/producers#produceblock}
  */
 export interface ProduceBlockSettingsWithAddons<
@@ -32,7 +33,7 @@ export interface ProduceBlockSettingsWithAddons<
 
 /**
  * Settings to run a Block with {@link produceBlock} that does not define addons.
- * @template Options Options values as described by the Block's Base's options schema.
+ * @template Options Options values as described by the Block's Base's options schema, as well as preset.
  * @see {@link https://www.create.bingo/engines/stratum/apis/producers#produceblock}
  */
 export interface ProduceBlockSettingsWithoutAddons<Options extends object> {
@@ -44,7 +45,7 @@ export interface ProduceBlockSettingsWithoutAddons<Options extends object> {
 /**
  * Produces a single Block that defines addons.
  * @template Addons Schema of Block-specific args defined by the Block, if defined.
- * @template Options Options values as described by the Block's Base's options schema.
+ * @template Options Options values as described by the Block's Base's options schema, as well as preset.
  * @see {@link https://www.create.bingo/engines/stratum/apis/producers#produceblock}
  */
 export function produceBlock<Addons extends object, Options extends object>(
@@ -53,7 +54,7 @@ export function produceBlock<Addons extends object, Options extends object>(
 ): Partial<BlockCreation<Options>>;
 /**
  * Produces a single Block that does not define addons.
- * @template Options Options values as described by the Block's Base's options schema.
+ * @template Options Options values as described by the Block's Base's options schema, as well as preset.
  * @see {@link https://www.create.bingo/engines/stratum/apis/producers#produceblock}
  */
 export function produceBlock<Options extends object>(
@@ -63,10 +64,13 @@ export function produceBlock<Options extends object>(
 /**
  * Produces a single Block.
  * @template Addons Schema of Block-specific args defined by the Block, if defined.
- * @template Options Options values as described by the Block's Base's options schema.
+ * @template Options Options values as described by the Block's Base's options schema, as well as preset.
  * @see {@link https://www.create.bingo/engines/stratum/apis/producers#produceblock}
  */
-export function produceBlock<Addons extends object, Options extends object>(
+export function produceBlock<
+	Addons extends object,
+	Options extends StratumTemplateOptions,
+>(
 	block: BlockWithAddons<Addons, Options> | BlockWithoutAddons<Options>,
 	settings: ProduceBlockSettings<Addons, Options>,
 ): Partial<BlockCreation<Options>> {
diff --git a/packages/bingo-stratum/src/types/blocks.ts b/packages/bingo-stratum/src/types/blocks.ts
index 914e9fd..0c08a1f 100644
--- a/packages/bingo-stratum/src/types/blocks.ts
+++ b/packages/bingo-stratum/src/types/blocks.ts
@@ -1,6 +1,7 @@
 import { AboutBase, AnyOptionalShape, InferredObject } from "bingo";
 
 import { BlockCreation, CreatedBlockAddons } from "./creations.js";
+import { StratumTemplateOptions } from "./templates.js";
 
 export type Block<
 	Addons extends object | undefined = object | undefined,
@@ -29,7 +30,6 @@ export interface BlockContextWithAddons<
 	Options extends object,
 > extends BlockContextWithoutAddons<Options> {
 	addons: Addons;
-	options: Options;
 }
 
 export interface BlockContextWithOptionalAddons<
@@ -37,12 +37,11 @@ export interface BlockContextWithOptionalAddons<
 	Options extends object,
 > extends BlockContextWithoutAddons<Options> {
 	addons?: Addons;
-	options: Options;
 }
 
 export interface BlockContextWithoutAddons<Options extends object> {
 	offline?: boolean;
-	options: Options;
+	options: Options & StratumTemplateOptions;
 }
 
 export type BlockDefinition<
diff --git a/packages/bingo-stratum/src/types/templates.ts b/packages/bingo-stratum/src/types/templates.ts
index 5a3ff11..713a2fb 100644
--- a/packages/bingo-stratum/src/types/templates.ts
+++ b/packages/bingo-stratum/src/types/templates.ts
@@ -11,33 +11,96 @@ import { Base } from "./bases.js";
 import { Preset } from "./presets.js";
 import { StratumRefinements } from "./refinements.js";
 
+/**
+ * Stratum Template grouping together Presets of Blocks created from a Base.
+ * @template OptionsShape Schemas of options the Base's Blocks takes in.
+ * @see {@link https://www.create.bingo/engines/stratum/concepts/templates}
+ */
 export interface StratumTemplate<OptionsShape extends AnyShape>
 	extends Template<
 		OptionsShape & StratumTemplateOptionsShape,
 		StratumRefinements<InferredObject<OptionsShape>>
 	> {
+	/**
+	 * Base creating this Template, as well as its Blocks and Presets.
+	 * @see {@link https://www.create.bingo/engines/stratum/concepts/bases}
+	 */
 	base: Base<OptionsShape>;
+
+	/**
+	 * Sets up lazily load default options values.
+	 * This is indicated as required here because all Stratum Templates infer
+	 * at least their --preset during transition mode.
+	 * @see {@link https://www.create.bingo/build/apis/create-template#prepare}
+	 */
 	prepare: TemplatePrepare<
 		InferredObject<OptionsShape>,
 		StratumRefinements<InferredObject<OptionsShape>>
 	>;
+
+	/**
+	 * The Presets users can choose from with the Template, in order of how they should be listed.
+	 * @see {@link https://www.create.bingo/engines/stratum/apis/create-base#createtemplate-presets}
+	 */
 	presets: Preset<OptionsShape>[];
 }
 
+/**
+ * Description of how to create a Stratum Template from a Base.
+ * @template OptionsShape Schemas of options the Base's Blocks takes in.
+ */
 export interface StratumTemplateDefinition<OptionsShape extends AnyShape> {
+	/**
+	 * About information for the template, including an optional repository locator.
+	 * @see {@link https://www.create.bingo/engines/stratum/apis/create-base#createtemplate-about}
+	 */
 	about?: TemplateAbout;
+
+	/**
+	 * Sets up lazily load default options values.
+	 * @see {@link https://www.create.bingo/engines/stratum/apis/create-base#createtemplate-prepare}
+	 */
 	prepare?: TemplatePrepare<
 		InferredObject<OptionsShape>,
 		StratumRefinements<InferredObject<OptionsShape>>
 	>;
+
+	/**
+	 * Presets users can choose from with the Template, in order of how they should be listed.
+	 * @see {@link https://www.create.bingo/engines/stratum/apis/create-base#createtemplate-presets}
+	 */
 	presets: Preset<OptionsShape>[];
+
+	/**
+	 * Suggested Preset to select by default for users, if not the first in the array.
+	 * @see {@link https://www.create.bingo/engines/stratum/apis/create-base#createtemplate-suggested}
+	 */
 	suggested?: Preset<OptionsShape>;
 }
 
+/**
+ * The minimal options that are passed to all Stratum Blocks.
+ */
+export interface StratumTemplateOptions {
+	/**
+	 * Which Preset is being run.
+	 */
+	preset: string;
+}
+
+/**
+ * The minimum options schemas all Stratum Templates share.
+ */
 export interface StratumTemplateOptionsShape {
+	/**
+	 * Union of Preset names available to choose from.
+	 */
 	preset: z.ZodDefault<z.ZodUnion<ZodPresetNameLiterals>>;
 }
 
+/**
+ * Union of at least two literal Preset names available to choose from.
+ */
 export type ZodPresetNameLiterals = [
 	z.ZodLiteral<string>,
 	z.ZodLiteral<string>,
diff --git a/packages/site/src/content/docs/build/apis/create-template.mdx b/packages/site/src/content/docs/build/apis/create-template.mdx
index 0ae2fe7..5610c77 100644
--- a/packages/site/src/content/docs/build/apis/create-template.mdx
+++ b/packages/site/src/content/docs/build/apis/create-template.mdx
@@ -234,7 +234,7 @@ Requiring the `owner` and `repository` fields be string-like allows [Setup mode]
 ### `prepare`
 
 Sets up lazily loaded default values for options.
-Receives an [Options Context](/build/details/contexts#options-contexts) and returns a [`Creation`](/build/concepts/creations).
+Receives an [Options Context](/build/details/contexts#options-contexts) and returns values or lazy functions for options values.
 
 Templates can optionally define a `prepare()` function that provides fallback values for options.
 Those values will be used if the user doesn't provide explicit values during creation.
diff --git a/packages/site/src/content/docs/engines/stratum/apis/create-base.mdx b/packages/site/src/content/docs/engines/stratum/apis/create-base.mdx
index c05e3f9..def466c 100644
--- a/packages/site/src/content/docs/engines/stratum/apis/create-base.mdx
+++ b/packages/site/src/content/docs/engines/stratum/apis/create-base.mdx
@@ -37,7 +37,7 @@ export const base = createBase({
 ```
 
 :::tip
-Base `option` are directly used as a [Template `options`](/build/apis/create-template#options) when a Stratum Template is generated.
+Base `options` are used as [Stratum Template `options`](/build/apis/create-template#options).
 :::
 
 ### `prepare` {#createbase-prepare}
@@ -69,7 +69,7 @@ export const base = createBase({
 ```
 
 :::tip
-Base `prepare()` functions are directly used as [Template `prepare()`](/build/apis/create-template#prepare) when a Stratum Template is generated.
+Base `prepare()` functions are used as [Stratum Template `prepare()`](/build/apis/create-template#prepare).
 :::
 
 ## `createBlock`
@@ -266,6 +266,42 @@ Repositories generated from that template would indicate _generated from [Joshua
 This is the same `about` field as the general Bingo [`createTemplate` API](/build/apis/create-template#about).
 :::
 
+### `prepare` {#createtemplate-prepare}
+
+Sets up lazily loaded default values for options.
+Receives an [Options Context](/build/details/contexts#options-contexts) and returns values or lazy functions for options values.
+
+Templates can optionally define a `prepare()` function that provides fallback values for options.
+Those values will be used if the user doesn't provide explicit values during creation.
+
+For example, this template defaults its `value` option to `"default"` if not provided:
+
+```ts
+import { createTemplate } from "bingo";
+
+export default createTemplate({
+	options: {
+		value: z.string().optional(),
+	},
+	prepare() {
+		return {
+			value: "default",
+		};
+	},
+	produce() {
+		// ...
+	},
+});
+```
+
+Running that template without an explicit `--value` would be equivalent to running with `--value "default"`.
+
+#### Preset Inference
+
+During transition mode, Stratum will attempt to infer a default value for `--preset` based using files on disk.
+That default value is computed by comparing existing files on disk to the files that would be produced by the Blocks.
+If Preset with the greatest percentage matches 35% or more of its created files, it will be used as the default.
+
 ### `presets` {#createtemplate-presets}
 
 The Presets users can choose from with the Template, in order of how they should be listed.
@@ -295,9 +331,9 @@ export const templateTypeScriptApp = base.createTemplate({
 
 ### `suggested` {#createtemplate-suggested}
 
-The suggested Preset to select for users, if not the first in the array.
+The suggested Preset to select for users by default, if not the first in the array.
 
-This should be the same string as one of the `labels` under [`presets`](#createtemplate-presets).
+This should be the same values as under [`presets`](#createtemplate-presets).
 
 For example, this Template defaults to the `"Common"` Preset:
 
diff --git a/packages/site/src/content/docs/engines/stratum/apis/producers.mdx b/packages/site/src/content/docs/engines/stratum/apis/producers.mdx
index 9eeb41f..9086a84 100644
--- a/packages/site/src/content/docs/engines/stratum/apis/producers.mdx
+++ b/packages/site/src/content/docs/engines/stratum/apis/producers.mdx
@@ -30,7 +30,7 @@ Given a [Block](/engines/stratum/concepts/blocks), creates a [Creation](/build/c
 `produceBlock` allows up to two parameters:
 
 1. `block` _(required)_: a Block
-2. `context` _(required)_: any properties from a [Block Context](/engines/stratum/details/contexts#block-contexts)
+2. `context` _(optional)_: any properties from a [Block Context](/engines/stratum/details/contexts#block-contexts)
 
 For example, given this Block that produces the start of a README.md file, `produceBlock` can run its `produce()` with any provided options:
 
@@ -119,7 +119,7 @@ produceBlock(blockInstallDependencies, { offline: true });
 
 ### `options` {#produceblock-options}
 
-Any number of options defined by the Block's [Base](/engines/stratum/concepts/bases).
+Any number of options defined by the Block's [Base](/engines/stratum/concepts/bases), as well as `preset: string`.
 
 For example, this Block is run with one `repository` option:
 
@@ -146,6 +146,7 @@ const blockPackageJson = createBlock({
 // { files: { "package.json": `{repository":"my-app"}` } }
 produceBlock(block, {
 	options: {
+		preset: "test",
 		repository: "my-app",
 	},
 });
@@ -198,7 +199,9 @@ declare const preset: Preset;
 
 producePreset(preset, {
 	offline: true,
-	options: {},
+	options: {
+		preset: "test",
+	},
 	preset: "example"
 });
 ```
@@ -210,7 +213,7 @@ If you are finding your Preset still sends requests offline, file a bug on the P
 
 ### `options` {#preset-options}
 
-Any options defined by the Preset's [Base](/engines/stratum/concepts/bases).
+Any options defined by the Preset's [Base](/engines/stratum/concepts/bases), as well as `preset: string`.
 
 This must include all required options from the Base.
 It may also include any other optional Options.
@@ -226,6 +229,7 @@ declare const preset: Preset<{ name: z.ZodString }>;
 producePreset(preset, {
 	options: {
 		name: "My Production",
+		preset: "test",
 	},
 	preset: "example",
 });
diff --git a/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum.mdx b/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum.mdx
index b3a7ddd..a059115 100644
--- a/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum.mdx
+++ b/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum.mdx
@@ -12,4 +12,4 @@ Highly composable, customizable templating engine for Bingo. 🏭
 See:
 
 - [Stratum > About](/engines/stratum/about) for starting documentation
-- [Stratum > APIs > Creators](/engines/stratum/apis/create-base) for creating templates with Stratum
+- [Stratum > APIs > `createBase`](/engines/stratum/apis/create-base) for creating templates with Stratum


Test patch:
diff --git a/packages/bingo-stratum-testers/src/testBlock.test.ts b/packages/bingo-stratum-testers/src/testBlock.test.ts
index ec467f7..0bd5703 100644
--- a/packages/bingo-stratum-testers/src/testBlock.test.ts
+++ b/packages/bingo-stratum-testers/src/testBlock.test.ts
@@ -47,7 +47,7 @@ describe("testBlock", () => {
 			},
 		});
 
-		it("does not throws an error when addons isn't provided and a block uses addons", () => {
+		it("does not throw an error when addons isn't provided and a block uses addons", () => {
 			const actual = testBlock(blockUsingAddons, {});
 
 			expect(actual).toMatchInlineSnapshot(`
@@ -73,7 +73,7 @@ describe("testBlock", () => {
 			produce({ options }) {
 				return {
 					files: {
-						"value.txt": options.value,
+						"value.txt": `${options.value} (${options.preset})`,
 					},
 				};
 			},
@@ -89,10 +89,12 @@ describe("testBlock", () => {
 
 		it("passes options to the block when provided", () => {
 			const actual = testBlock(blockUsingOptions, {
-				options: { value: "abc" },
+				options: { preset: "test", value: "abc" },
 			});
 
-			expect(actual).toEqual({ files: { "value.txt": "abc" } });
+			expect(actual).toEqual({
+				files: { "value.txt": "abc (test)" },
+			});
 		});
 	});
 });
diff --git a/packages/bingo-stratum-testers/src/testBlock.ts b/packages/bingo-stratum-testers/src/testBlock.ts
index 73f44b7..9b94c23 100644
--- a/packages/bingo-stratum-testers/src/testBlock.ts
+++ b/packages/bingo-stratum-testers/src/testBlock.ts
@@ -6,6 +6,7 @@ import {
 	ProduceBlockSettingsWithAddons,
 } from "bingo-stratum";
 import { BlockCreation } from "bingo-stratum/lib/types/creations.js";
+import { StratumTemplateOptions } from "bingo-stratum/lib/types/templates.js";
 
 import { createFailingObject } from "./utils.js";
 
@@ -19,7 +20,7 @@ export interface BlockContextSettingsWithOptionalAddons<
 export interface BlockContextSettingsWithoutAddons<Options extends object> {
 	mode?: ProductionMode;
 	offline?: boolean;
-	options?: Options;
+	options?: Options & StratumTemplateOptions;
 }
 
 export function testBlock<Addons extends object, Options extends object>(
diff --git a/packages/bingo-stratum/src/creators/createBase.test.ts b/packages/bingo-stratum/src/creators/createBase.test.ts
index 0061859..5c60537 100644
--- a/packages/bingo-stratum/src/creators/createBase.test.ts
+++ b/packages/bingo-stratum/src/creators/createBase.test.ts
@@ -15,17 +15,19 @@ describe("createBase", () => {
 					produce({ options }) {
 						return {
 							files: {
-								"name.txt": options.name,
+								"name.txt": `${options.name} (${options.preset})`,
 							},
 						};
 					},
 				});
 
-				const production = block.produce({ options: { name: "abc" } });
+				const production = block.produce({
+					options: { name: "abc", preset: "test" },
+				});
 
 				expect(production).toEqual({
 					files: {
-						"name.txt": "abc",
+						"name.txt": "abc (test)",
 					},
 				});
 			});
@@ -42,7 +44,9 @@ describe("createBase", () => {
 
 						return {
 							files: {
-								"names.txt": [options.name, ...names].join("\n"),
+								"names.txt": [options.preset, options.name, ...names].join(
+									"\n",
+								),
 							},
 						};
 					},
@@ -50,12 +54,12 @@ describe("createBase", () => {
 
 				const production = block.produce({
 					addons: { names: ["def"] },
-					options: { name: "abc" },
+					options: { name: "abc", preset: "test" },
 				});
 
 				expect(production).toEqual({
 					files: {
-						"names.txt": "abc\ndef",
+						"names.txt": "test\nabc\ndef",
 					},
 				});
 			});
diff --git a/packages/bingo-stratum/src/creators/createBlock.test.ts b/packages/bingo-stratum/src/creators/createBlock.test.ts
new file mode 100644
index 0000000..28fdb37
--- /dev/null
+++ b/packages/bingo-stratum/src/creators/createBlock.test.ts
@@ -0,0 +1,63 @@
+import { describe, expect, it } from "vitest";
+import { z } from "zod";
+
+import { createBlock } from "./createBlock.js";
+
+describe("createBlock", () => {
+	describe("without Addons", () => {
+		it("produces without Addons", () => {
+			const block = createBlock<{ name: string }>({
+				produce({ options }) {
+					return {
+						files: {
+							"name.txt": `${options.name} (${options.preset})`,
+						},
+					};
+				},
+			});
+
+			const production = block.produce({
+				options: { name: "abc", preset: "test" },
+			});
+
+			expect(production).toEqual({
+				files: {
+					"name.txt": "abc (test)",
+				},
+			});
+		});
+	});
+
+	describe("with Addons", () => {
+		it("applies Zod defaults when producing with Addons", () => {
+			const block = createBlock<
+				{ names: z.ZodDefault<z.ZodArray<z.ZodString>> },
+				{ name: string }
+			>({
+				addons: {
+					names: z.array(z.string()).default([]),
+				},
+				produce({ addons, options }) {
+					const { names } = addons;
+
+					return {
+						files: {
+							"names.txt": [options.preset, options.name, ...names].join("\n"),
+						},
+					};
+				},
+			});
+
+			const production = block.produce({
+				addons: { names: ["def"] },
+				options: { name: "abc", preset: "test" },
+			});
+
+			expect(production).toEqual({
+				files: {
+					"names.txt": "test\nabc\ndef",
+				},
+			});
+		});
+	});
+});
diff --git a/packages/bingo-stratum/src/producers/produceStratumTemplate.test.ts b/packages/bingo-stratum/src/producers/produceStratumTemplate.test.ts
index a2c272b..4fc8319 100644
--- a/packages/bingo-stratum/src/producers/produceStratumTemplate.test.ts
+++ b/packages/bingo-stratum/src/producers/produceStratumTemplate.test.ts
@@ -56,7 +56,7 @@ describe("produceStratumTemplate", () => {
 			produce({ options }) {
 				return {
 					files: {
-						"value.txt": options.value,
+						"value.txt": `${options.value} (${options.preset})`,
 					},
 				};
 			},
@@ -80,7 +80,7 @@ describe("produceStratumTemplate", () => {
 
 		expect(actual).toEqual({
 			files: {
-				"value.txt": "abc",
+				"value.txt": "abc (test)",
 			},
 		});
 	});
diff --git a/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum-testers.mdx b/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum-testers.mdx
index 976dba5..016137a 100644
--- a/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum-testers.mdx
+++ b/packages/site/src/content/docs/engines/stratum/packages/bingo-stratum-testers.mdx
@@ -115,7 +115,7 @@ describe("blockPrettier", () => {
 
 ### `options` {#testblock-options}
 
-[Base Options](/engines/stratum/concepts/bases#options) may be provided under `options`.
+[Base Options](/engines/stratum/concepts/bases#options) may be provided under `options`, as well as `preset: string`.
 
 For example, this test asserts that a README.md uses the `title` defined under `options`:
 
@@ -129,7 +129,7 @@ const blockReadme = base.createBlock({
 	produce({ options }) {
 		return {
 			files: {
-				"README.md": `# ${options.title}`,
+				"README.md": `# ${options.title} (${options.preset})`,
 			},
 		};
 	},
@@ -139,13 +139,14 @@ describe("blockDocs", () => {
 	it("uses options.name for the README.md title", async () => {
 		const actual = await testBlock(blockReadme, {
 			options: {
+				preset: "test",
 				title: "My Project",
 			},
 		});
 
 		expect(actual).toEqual({
 			files: {
-				"README.md": `# My Project`,
+				"README.md": `# My Project (test)`,
 			},
 		});
 	});