humanish 0.38.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +5 -2
  2. package/dist/actor-contract.d.ts +24 -1
  3. package/dist/actor-contract.js +4 -0
  4. package/dist/actor-contract.js.map +1 -1
  5. package/dist/claude-agent-sdk.js +4 -0
  6. package/dist/claude-agent-sdk.js.map +1 -1
  7. package/dist/comms-catch-host.d.ts +31 -0
  8. package/dist/comms-catch-host.js +82 -4
  9. package/dist/comms-catch-host.js.map +1 -1
  10. package/dist/comms-sandbox-catch.d.ts +32 -1
  11. package/dist/comms-sandbox-catch.js +226 -19
  12. package/dist/comms-sandbox-catch.js.map +1 -1
  13. package/dist/computer-use-actor.d.ts +1 -1
  14. package/dist/computer-use.d.ts +13 -1
  15. package/dist/computer-use.js +100 -14
  16. package/dist/computer-use.js.map +1 -1
  17. package/dist/concurrent-shared-world-lab.js +7 -2
  18. package/dist/concurrent-shared-world-lab.js.map +1 -1
  19. package/dist/cua-actor-lab.d.ts +8 -0
  20. package/dist/cua-actor-lab.js +110 -9
  21. package/dist/cua-actor-lab.js.map +1 -1
  22. package/dist/e2b-desktop-executor.d.ts +21 -6
  23. package/dist/e2b-desktop-executor.js +65 -21
  24. package/dist/e2b-desktop-executor.js.map +1 -1
  25. package/dist/lab-config.d.ts +36 -0
  26. package/dist/lab-config.js +87 -2
  27. package/dist/lab-config.js.map +1 -1
  28. package/dist/observer-data.js +5 -0
  29. package/dist/observer-data.js.map +1 -1
  30. package/dist/openai-responses-cu.js +10 -1
  31. package/dist/openai-responses-cu.js.map +1 -1
  32. package/dist/orientation.d.ts +29 -0
  33. package/dist/orientation.js +95 -0
  34. package/dist/orientation.js.map +1 -0
  35. package/dist/persona-resolve.d.ts +44 -0
  36. package/dist/persona-resolve.js +109 -0
  37. package/dist/persona-resolve.js.map +1 -0
  38. package/dist/pi-agent-core.js +4 -0
  39. package/dist/pi-agent-core.js.map +1 -1
  40. package/dist/pricing.d.ts +8 -0
  41. package/dist/pricing.js +22 -6
  42. package/dist/pricing.js.map +1 -1
  43. package/dist/program.js +36 -1
  44. package/dist/program.js.map +1 -1
  45. package/dist/run.d.ts +1 -1
  46. package/dist/run.js +27 -1
  47. package/dist/run.js.map +1 -1
  48. package/dist/shared-world-lab.js +7 -2
  49. package/dist/shared-world-lab.js.map +1 -1
  50. package/dist/subject-runtime.d.ts +23 -0
  51. package/dist/subject-runtime.js +70 -0
  52. package/dist/subject-runtime.js.map +1 -0
  53. package/docs/contracts/schemas.md +1 -1
  54. package/docs/goals/current.md +2 -2
  55. package/docs/principles/three-roles.md +68 -0
  56. package/docs/ramp/README.md +1 -1
  57. package/package.json +1 -1
@@ -91,11 +91,26 @@ export declare class CuaTypeFallbackError extends Error {
91
91
  */
92
92
  export declare function createE2BDesktopExecutor(desktop: E2BDesktopLike, options?: E2BDesktopExecutorOptions): CuaExecutor;
93
93
  /**
94
- * A coarse perceptual hash of a PNG frame for no-progress detection. Decodes the
95
- * PNG, area-averages it to a SIGNATURE_GRID x SIGNATURE_GRID grayscale grid,
96
- * quantizes each cell to 2 bits (gray >> 6, four levels), and packs the
97
- * (SIGNATURE_GRID^2) two-bit cells into a compact hex string. Deterministic (no
98
- * Date, no random). Returns SIGNATURE_FALLBACK on any decode failure so two
99
- * unreadable frames compare equal.
94
+ * A perceptual hash of a PNG frame for no-progress detection. Decodes the PNG, area-averages it to
95
+ * a SIGNATURE_GRID x SIGNATURE_GRID grayscale grid, CONTRAST-NORMALIZES that grid, quantizes each
96
+ * cell to SIGNATURE_LEVELS, and packs the cells into a hex string. Deterministic (no Date, no
97
+ * random). Returns SIGNATURE_FALLBACK on any decode failure so two unreadable frames compare equal.
98
+ *
99
+ * Why normalization, and why this grid (#383). The original was 16x16 at 2 bits per cell with no
100
+ * normalization. On a 1440x950 desktop that is one cell per ~90x59 px, and on a light-themed web app
101
+ * the area-average of nearly every cell lands at the top of the range: a measured run had 93% of the
102
+ * 256 cells pinned to level 3 and levels 0 and 1 never used at all. The hash was effectively a
103
+ * constant, so renaming a row in a sidebar, adding a list item, or opening a small panel could not
104
+ * move it — 22 frames across one run produced 5 distinct values, and 9 visibly different consecutive
105
+ * frames produced ONE. The no-progress backstop read that as a stuck agent and ended a lane that was
106
+ * a foreign key away from finishing its mission.
107
+ *
108
+ * Stretching each frame's own min..max across the full range before quantizing is what makes a
109
+ * mostly-white UI use the levels it actually has, and the finer grid shrinks a cell to ~45x30 px so
110
+ * ordinary widget-sized changes survive the averaging.
111
+ *
112
+ * This is still a coarse whole-frame hash and it is still only ONE input to the backstop — see the
113
+ * corroboration rule in computer-use.ts, which is what keeps a blind frame from ending a run on its
114
+ * own.
100
115
  */
101
116
  export declare function perceptualSignature(pngBytes: Buffer | Uint8Array): string;
@@ -235,15 +235,31 @@ export function createE2BDesktopExecutor(desktop, options = {}) {
235
235
  // the image, so exposing it (e.g. in a trace) is public-safe. On any decode
236
236
  // failure it returns a stable fallback so two unreadable frames compare equal.
237
237
  // ---------------------------------------------------------------------------
238
- const SIGNATURE_GRID = 16;
238
+ const SIGNATURE_GRID = 32;
239
+ const SIGNATURE_LEVELS = 16;
239
240
  const SIGNATURE_FALLBACK = "unreadable";
240
241
  /**
241
- * A coarse perceptual hash of a PNG frame for no-progress detection. Decodes the
242
- * PNG, area-averages it to a SIGNATURE_GRID x SIGNATURE_GRID grayscale grid,
243
- * quantizes each cell to 2 bits (gray >> 6, four levels), and packs the
244
- * (SIGNATURE_GRID^2) two-bit cells into a compact hex string. Deterministic (no
245
- * Date, no random). Returns SIGNATURE_FALLBACK on any decode failure so two
246
- * unreadable frames compare equal.
242
+ * A perceptual hash of a PNG frame for no-progress detection. Decodes the PNG, area-averages it to
243
+ * a SIGNATURE_GRID x SIGNATURE_GRID grayscale grid, CONTRAST-NORMALIZES that grid, quantizes each
244
+ * cell to SIGNATURE_LEVELS, and packs the cells into a hex string. Deterministic (no Date, no
245
+ * random). Returns SIGNATURE_FALLBACK on any decode failure so two unreadable frames compare equal.
246
+ *
247
+ * Why normalization, and why this grid (#383). The original was 16x16 at 2 bits per cell with no
248
+ * normalization. On a 1440x950 desktop that is one cell per ~90x59 px, and on a light-themed web app
249
+ * the area-average of nearly every cell lands at the top of the range: a measured run had 93% of the
250
+ * 256 cells pinned to level 3 and levels 0 and 1 never used at all. The hash was effectively a
251
+ * constant, so renaming a row in a sidebar, adding a list item, or opening a small panel could not
252
+ * move it — 22 frames across one run produced 5 distinct values, and 9 visibly different consecutive
253
+ * frames produced ONE. The no-progress backstop read that as a stuck agent and ended a lane that was
254
+ * a foreign key away from finishing its mission.
255
+ *
256
+ * Stretching each frame's own min..max across the full range before quantizing is what makes a
257
+ * mostly-white UI use the levels it actually has, and the finer grid shrinks a cell to ~45x30 px so
258
+ * ordinary widget-sized changes survive the averaging.
259
+ *
260
+ * This is still a coarse whole-frame hash and it is still only ONE input to the backstop — see the
261
+ * corroboration rule in computer-use.ts, which is what keeps a blind frame from ending a run on its
262
+ * own.
247
263
  */
248
264
  export function perceptualSignature(pngBytes) {
249
265
  let cells;
@@ -257,15 +273,15 @@ export function perceptualSignature(pngBytes) {
257
273
  if (!srcW || !srcH)
258
274
  return SIGNATURE_FALLBACK;
259
275
  cells = quantizedGrid(decoded.data, srcW, srcH);
276
+ return `${brightnessAnchor(decoded.data, srcW, srcH)}${packCells(cells)}`;
260
277
  }
261
278
  catch {
262
279
  return SIGNATURE_FALLBACK;
263
280
  }
264
- return packCells(cells);
265
281
  }
266
- /** Area-average an RGBA buffer to a grid of 2-bit (0..3) grayscale cells. */
282
+ /** Area-average an RGBA buffer to a grid of grayscale cells, contrast-normalized then quantized. */
267
283
  function quantizedGrid(data, srcW, srcH) {
268
- const cells = [];
284
+ const grays = [];
269
285
  const xRatio = srcW / SIGNATURE_GRID;
270
286
  const yRatio = srcH / SIGNATURE_GRID;
271
287
  for (let gy = 0; gy < SIGNATURE_GRID; gy += 1) {
@@ -286,22 +302,50 @@ function quantizedGrid(data, srcW, srcH) {
286
302
  n += 1;
287
303
  }
288
304
  }
289
- const gray = n ? Math.round(sum / n) : 0;
290
- // Quantize 0..255 to four levels (0..3). Clamp the 255 edge so it stays in
291
- // range (255 >> 6 === 3 already, but Math.min guards any rounding surprise).
292
- cells.push(Math.min(3, gray >> 6));
305
+ grays.push(n ? Math.round(sum / n) : 0);
293
306
  }
294
307
  }
295
- return cells;
308
+ // Stretch this frame's own range across the full scale before quantizing. Without this a light UI
309
+ // occupies a sliver at the top of 0..255 and quantizes to a near-constant (#383).
310
+ //
311
+ // The endpoints are TRIMMED rather than the raw min/max: a handful of extreme cells must not be
312
+ // able to rescale the whole frame, or a blinking text cursor would rewrite every cell and read as
313
+ // progress forever. Trimming K cells from each end clamps that away while still preserving real
314
+ // structure, which occupies far more cells than K (a row of sidebar text covers dozens).
315
+ const sorted = [...grays].sort((a, b) => a - b);
316
+ const trim = Math.max(2, Math.floor(sorted.length / 256));
317
+ const lo = sorted[Math.min(trim, sorted.length - 1)] ?? 0;
318
+ const hi = sorted[Math.max(0, sorted.length - 1 - trim)] ?? 255;
319
+ const span = hi - lo;
320
+ const top = SIGNATURE_LEVELS - 1;
321
+ return grays.map((gray) => span <= 0 ? 0 : Math.min(top, Math.max(0, Math.round(((gray - lo) / span) * top))));
296
322
  }
297
- /** Pack 2-bit cells (4 per hex... actually 2 per byte) into a compact hex string. */
323
+ /**
324
+ * The frame's overall brightness, coarsely quantized. Normalization deliberately discards absolute
325
+ * level, so this is prefixed back on for the two cases where absolute level IS the change: a uniform
326
+ * frame (an all-white blank vs an all-black screen normalize identically), and a whole-page dim such
327
+ * as a modal overlay, which preserves relative structure while changing the whole frame. Quantized
328
+ * coarsely so ordinary antialiasing noise cannot move it.
329
+ */
330
+ function brightnessAnchor(data, srcW, srcH) {
331
+ let sum = 0;
332
+ let n = 0;
333
+ const stride = Math.max(1, Math.floor((srcW * srcH) / 4096));
334
+ for (let p = 0; p < srcW * srcH; p += stride) {
335
+ const si = p * 4;
336
+ sum += ((data[si] ?? 0) + (data[si + 1] ?? 0) + (data[si + 2] ?? 0)) / 3;
337
+ n += 1;
338
+ }
339
+ const mean = n ? sum / n : 0;
340
+ return (Math.min(15, Math.floor(mean / 16))).toString(16);
341
+ }
342
+ /** Pack 4-bit cells (two per byte) into a compact hex string. */
298
343
  function packCells(cells) {
299
- // Pack four 2-bit cells per byte, then hex-encode. SIGNATURE_GRID^2 cells.
300
- const bytes = Buffer.alloc(Math.ceil(cells.length / 4));
344
+ const bytes = Buffer.alloc(Math.ceil(cells.length / 2));
301
345
  for (let i = 0; i < cells.length; i += 1) {
302
- const byteIndex = i >> 2;
303
- const shift = (i & 3) * 2;
304
- const value = (cells[i] ?? 0) & 3;
346
+ const byteIndex = i >> 1;
347
+ const shift = (i & 1) * 4;
348
+ const value = (cells[i] ?? 0) & 0xf;
305
349
  bytes[byteIndex] = (bytes[byteIndex] ?? 0) | (value << shift);
306
350
  }
307
351
  return bytes.toString("hex");
@@ -1 +1 @@
1
- {"version":3,"file":"e2b-desktop-executor.js","sourceRoot":"","sources":["../src/e2b-desktop-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"e2b-desktop-executor.js","sourceRoot":"","sources":["../src/e2b-desktop-executor.ts"],"names":[],"mappings":"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"}
@@ -200,6 +200,17 @@ export interface LabSubject {
200
200
  * on the computer-use clone route.
201
201
  */
202
202
  env?: string[];
203
+ /**
204
+ * LITERAL, NON-SECRET env values committed alongside the lab — the configuration every real app
205
+ * needs before it will boot: a public base URL, a transport selector, a feature flag. None of that
206
+ * is secret, and routing it through `subject.env` would force an adopter to carry a private env
207
+ * file just to reproduce a public study, which is the opposite of a reproducible lab.
208
+ *
209
+ * These values ARE recorded in evidence, because they are part of how the subject was configured,
210
+ * so a value that looks like a secret or a local path is refused at parse rather than committed to
211
+ * a public repo. Anything genuinely secret belongs in `subject.env`.
212
+ */
213
+ envValues?: Record<string, string>;
203
214
  /**
204
215
  * `clone` (computer-use route): the subject's state story — seed/migration/fixture steps
205
216
  * executed in-sandbox around the serve sequence, and/or declared external state. Recorded
@@ -496,6 +507,21 @@ export interface LabDefaults {
496
507
  export interface LabComms {
497
508
  email?: LabCommsEmail;
498
509
  }
510
+ export interface LabCommsSmtp {
511
+ /** Fixed in-sandbox loopback SMTP port (default 2525). Known before sandbox create, like `port`. */
512
+ port?: number;
513
+ /** The subject-env var carrying the SMTP host. The harness sets it to 127.0.0.1. */
514
+ hostEnv: string;
515
+ /** The subject-env var carrying the SMTP port. The harness sets it to the port above. */
516
+ portEnv: string;
517
+ /** Optional subject-env vars for a username/password the app insists on sending. The catch accepts
518
+ * any credentials (it is loopback-only), but many apps refuse to start without the vars set. */
519
+ userEnv?: string;
520
+ passwordEnv?: string;
521
+ /** The value written to `userEnv`/`passwordEnv` when those are declared. Never a real secret. */
522
+ user?: string;
523
+ password?: string;
524
+ }
499
525
  export interface LabCommsEmail {
500
526
  /** Which implementation backs the inbox (a backend discriminator, distinct from `scenario.mode`):
501
527
  * `fake` (default) is an in-harness in-memory inbox in the Fowler test-double sense — an in-sandbox
@@ -512,6 +538,16 @@ export interface LabCommsEmail {
512
538
  injectEnv?: string;
513
539
  /** Fixed in-sandbox loopback port the catch listens on (default 8025). Known before sandbox create. */
514
540
  port?: number;
541
+ /**
542
+ * SMTP transport, for the many self-hostable apps that send mail through SMTP rather than a
543
+ * provider's HTTP API. The catch opens a loopback SMTP listener and normalizes what it receives
544
+ * into the same captured-send shape the HTTP path produces, so the inbox surface, the drain, and
545
+ * the evidence artifact are identical either way.
546
+ *
547
+ * `hostEnv` and `portEnv` are ADOPTER-NAMED, exactly like `injectEnv`: the harness sets them to
548
+ * its own loopback and the chosen port. Declare the pair your app actually reads.
549
+ */
550
+ smtp?: LabCommsSmtp;
515
551
  /** Optional escape hatch: the exact absolute origin the app-under-test bakes into its email verify
516
552
  * links, when that differs from the serve origin (e.g. an app configured with an absolute
517
553
  * APP_URL/NEXT_PUBLIC_BASE_URL). The harness cannot infer it, so the operator declares it; it is
@@ -48,6 +48,7 @@
48
48
  // bump the version honestly.
49
49
  import { normalizeExtraExcludeEntry } from "./source-archive.js";
50
50
  import { actorRegistry } from "./actor-registry.js";
51
+ import { containsSensitive } from "./redaction.js";
51
52
  import { DEVICE_PRESET_NAMES, isDevicePresetName } from "./device-presets.js";
52
53
  export const LAB_CONFIG_SCHEMA = "humanish.lab.v2";
53
54
  // Must start alphanumeric so an id never collides with the path-vs-id resolver heuristic
@@ -1108,6 +1109,11 @@ function parseSubject(raw) {
1108
1109
  }
1109
1110
  subject.env = env;
1110
1111
  }
1112
+ const envValuesResult = parseEnvValues(raw.envValues);
1113
+ if (!envValuesResult.ok)
1114
+ return envValuesResult;
1115
+ if (envValuesResult.value)
1116
+ subject.envValues = envValuesResult.value;
1111
1117
  const stateResult = parseState(raw.state);
1112
1118
  if (!stateResult.ok) {
1113
1119
  return stateResult;
@@ -1145,6 +1151,11 @@ function parseSubject(raw) {
1145
1151
  }
1146
1152
  subject.env = env;
1147
1153
  }
1154
+ const envValuesResult = parseEnvValues(raw.envValues);
1155
+ if (!envValuesResult.ok)
1156
+ return envValuesResult;
1157
+ if (envValuesResult.value)
1158
+ subject.envValues = envValuesResult.value;
1148
1159
  const stateResult = parseState(raw.state);
1149
1160
  if (!stateResult.ok) {
1150
1161
  return stateResult;
@@ -1308,6 +1319,38 @@ function parseServe(raw) {
1308
1319
  * them) so subjectStateInvalidReason rejects them — a state declaration that silently does
1309
1320
  * less than it says would violate invariant 6.
1310
1321
  */
1322
+ /**
1323
+ * LITERAL non-secret subject env. Real apps need configuration before they will boot — a public base
1324
+ * URL, a transport selector, a feature flag — and none of that is secret. Routing it through
1325
+ * `subject.env` would force an adopter to carry a private env file just to reproduce a public study.
1326
+ *
1327
+ * These values ARE recorded in evidence (they are part of how the subject was configured), so a
1328
+ * value that looks like a credential is refused here rather than committed to a public repo.
1329
+ */
1330
+ function parseEnvValues(raw) {
1331
+ if (raw === undefined)
1332
+ return { ok: true };
1333
+ if (!isRecord(raw)) {
1334
+ return invalid("`subject.envValues` must be a mapping of env var NAME to a literal non-secret value.");
1335
+ }
1336
+ const envValues = {};
1337
+ for (const [name, rawValue] of Object.entries(raw)) {
1338
+ if (!ENV_NAME_PATTERN.test(name)) {
1339
+ return invalid(`subject.envValues keys must be env var NAMES like NEXT_PUBLIC_APP_URL (got "${name}").`);
1340
+ }
1341
+ const value = typeof rawValue === "number" || typeof rawValue === "boolean" ? String(rawValue) : str(rawValue);
1342
+ if (value === undefined) {
1343
+ return invalid(`\`subject.envValues.${name}\` must be a string, number, or boolean.`);
1344
+ }
1345
+ // Reuse the redaction module's own detector rather than inventing a second opinion about what
1346
+ // a secret looks like — the two must never disagree about the same string.
1347
+ if (containsSensitive(value)) {
1348
+ return invalid(`\`subject.envValues.${name}\` looks like a secret or a local path, and these values are committed with the lab and recorded in evidence. Declare the NAME in \`subject.env\` instead — those values come from the caller's environment and never persist.`);
1349
+ }
1350
+ envValues[name] = value;
1351
+ }
1352
+ return { ok: true, value: envValues };
1353
+ }
1311
1354
  function parseState(raw) {
1312
1355
  if (raw === undefined) {
1313
1356
  return { ok: true, value: undefined };
@@ -2106,9 +2149,50 @@ function parseCommsEmail(raw) {
2106
2149
  ...(authTokenEnv === undefined ? {} : { authTokenEnv })
2107
2150
  };
2108
2151
  }
2152
+ // SMTP transport, for apps that send mail through SMTP rather than a provider's HTTP API.
2153
+ let smtp;
2154
+ if (raw.smtp !== undefined) {
2155
+ if (!isRecord(raw.smtp))
2156
+ return invalid("`comms.email.smtp` must be a mapping.");
2157
+ const envName = (value, field) => {
2158
+ const name = str(value);
2159
+ if (name === undefined)
2160
+ return undefined;
2161
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `__invalid__${field}`;
2162
+ };
2163
+ const hostEnv = envName(raw.smtp.hostEnv, "hostEnv");
2164
+ const portEnv = envName(raw.smtp.portEnv, "portEnv");
2165
+ if (hostEnv === undefined || portEnv === undefined) {
2166
+ return invalid("`comms.email.smtp` needs both `hostEnv` and `portEnv` — the subject-env vars your app reads for its SMTP host and port. The harness sets them to its own loopback listener.");
2167
+ }
2168
+ if (hostEnv.startsWith("__invalid__") || portEnv.startsWith("__invalid__")) {
2169
+ return invalid("`comms.email.smtp.hostEnv` and `portEnv` must be valid env var names.");
2170
+ }
2171
+ let smtpPort = 2525;
2172
+ if (raw.smtp.port !== undefined) {
2173
+ const parsed = posInt(raw.smtp.port);
2174
+ if (parsed === undefined || parsed > 65_535)
2175
+ return invalid("`comms.email.smtp.port` must be a positive integer ≤ 65535.");
2176
+ smtpPort = parsed;
2177
+ }
2178
+ const userEnv = envName(raw.smtp.userEnv, "userEnv");
2179
+ const passwordEnv = envName(raw.smtp.passwordEnv, "passwordEnv");
2180
+ if (userEnv?.startsWith("__invalid__") || passwordEnv?.startsWith("__invalid__")) {
2181
+ return invalid("`comms.email.smtp.userEnv` and `passwordEnv` must be valid env var names.");
2182
+ }
2183
+ smtp = {
2184
+ port: smtpPort,
2185
+ hostEnv,
2186
+ portEnv,
2187
+ ...(userEnv === undefined ? {} : { userEnv }),
2188
+ ...(passwordEnv === undefined ? {} : { passwordEnv }),
2189
+ ...(str(raw.smtp.user) === undefined ? {} : { user: str(raw.smtp.user) }),
2190
+ ...(str(raw.smtp.password) === undefined ? {} : { password: str(raw.smtp.password) })
2191
+ };
2192
+ }
2109
2193
  const injectEnv = str(raw.injectEnv);
2110
- if (injectEnv === undefined && external === undefined) {
2111
- return invalid("`comms.email.injectEnv` is required the subject-env var the harness sets to the catch base URL (e.g. RESEND_API_URL). On an adopter-hosted plane declare `comms.email.external` instead: you run the catch and point your own app at it.");
2194
+ if (injectEnv === undefined && external === undefined && smtp === undefined) {
2195
+ return invalid("`comms.email` needs a transport: `injectEnv` (the subject-env var set to the catch's HTTP base URL, e.g. RESEND_BASE_URL), or `smtp` (host/port env vars, for an app that sends over SMTP), or `external` on an adopter-hosted plane where you run the catch yourself.");
2112
2196
  }
2113
2197
  if (injectEnv !== undefined && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(injectEnv)) {
2114
2198
  return invalid(`\`comms.email.injectEnv\` must be a valid env var name (got "${injectEnv}").`);
@@ -2116,6 +2200,7 @@ function parseCommsEmail(raw) {
2116
2200
  const email = {
2117
2201
  kind: "fake",
2118
2202
  ...(injectEnv === undefined ? {} : { injectEnv }),
2203
+ ...(smtp === undefined ? {} : { smtp }),
2119
2204
  ...(external === undefined ? {} : { external })
2120
2205
  };
2121
2206
  if (raw.port !== undefined) {