@volter/twin-standard 1.0.159 → 1.0.160

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 (52) hide show
  1. package/dist/src/check-sources.js +2 -2
  2. package/dist/src/clients/resend.first-use.json +2 -2
  3. package/dist/src/conformance.d.ts +1 -4
  4. package/dist/src/conformance.js +4 -19
  5. package/dist/src/create-pack.d.ts +1 -1
  6. package/dist/src/create-pack.js +13 -12
  7. package/dist/src/derive.js +3 -3
  8. package/dist/src/index.d.ts +1 -1
  9. package/dist/src/index.js +1 -1
  10. package/dist/src/pack-facts.d.ts +3 -0
  11. package/dist/src/pack-facts.js +36 -1
  12. package/dist/src/protocol-3.js +5 -5
  13. package/dist/src/spec-ir-client.js +1 -1
  14. package/dist/src/spec-ir-commands.js +1 -1
  15. package/dist/src/spec-ir-lines.js +1 -1
  16. package/dist/src/spec-ir-proto.d.ts +1 -1
  17. package/dist/src/spec-patches.js +2 -2
  18. package/dist/src/tools/judge-brief.js +1 -2
  19. package/dist/src/tools/life-coverage.js +2 -2
  20. package/dist/src/tools/packs-root.js +3 -3
  21. package/dist/src/tools/score-pack.js +1 -2
  22. package/dist/src/tools/vendor-examples.js +4 -5
  23. package/dist/src/verdict.js +1 -1
  24. package/dist/src/walk/behavior-journey.js +18 -1
  25. package/dist/src/walk/journey-kit.d.ts +2 -2
  26. package/dist/src/walk/serve-pack.js +6 -0
  27. package/dist/src/walk/shape.d.ts +1 -1
  28. package/dist/src/walk/shape.js +1 -1
  29. package/package.json +6 -4
  30. package/src/check-sources.ts +2 -2
  31. package/src/clients/resend.first-use.json +2 -2
  32. package/src/conformance.ts +4 -19
  33. package/src/create-pack.ts +13 -12
  34. package/src/derive.ts +3 -3
  35. package/src/index.ts +1 -1
  36. package/src/pack-facts.ts +25 -2
  37. package/src/protocol-3.ts +5 -5
  38. package/src/spec-ir-client.ts +1 -1
  39. package/src/spec-ir-commands.ts +1 -1
  40. package/src/spec-ir-lines.ts +1 -1
  41. package/src/spec-ir-proto.ts +1 -1
  42. package/src/spec-patches.ts +2 -2
  43. package/src/tools/judge-brief.ts +1 -2
  44. package/src/tools/life-coverage.ts +2 -2
  45. package/src/tools/packs-root.ts +3 -3
  46. package/src/tools/score-pack.ts +1 -2
  47. package/src/tools/vendor-examples.ts +4 -5
  48. package/src/verdict.ts +1 -1
  49. package/src/walk/behavior-journey.ts +14 -1
  50. package/src/walk/journey-kit.ts +2 -2
  51. package/src/walk/serve-pack.ts +5 -0
  52. package/src/walk/shape.ts +1 -1
@@ -10,13 +10,13 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
10
10
  // check-sources — the evidence a derived pack cites, fetched (docs/contributing/architecture.md,
11
11
  // "Protocol 3", Correcting the spec and The semantics layer). Every URL a state transition's `source`,
12
12
  // a handler's `// source:` line or a spec patch's `why` names is fetched once and its answer recorded in `spec/sources.json`; a patch's
13
- // `quote` is looked for in the text of the page its `source` names. derive-pack reads the record offline
13
+ // `quote` is looked for in the text of the page its `source` names. the derivation reads the record offline
14
14
  // and refuses a dead source, one never checked, and a quote its page does not hold.
15
15
  //
16
16
  // Documentation pages, never a vendor's API: each is fetched at most once per run, sixteen at a time,
17
17
  // and a page already recorded as found is not fetched again (--recheck fetches everything).
18
18
  //
19
- // Usage: twin-standard check-sources <pack dir> [--recheck] (twin-world: bun scripts/check-sources.ts <vendor>)
19
+ // Usage: twin-standard check-sources <pack dir> [--recheck]
20
20
  import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
21
21
  import { dirname, join } from 'node:path';
22
22
  import { unitAt } from "./unit.js";
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "source": "https://www.npmjs.com/package/resend/v/6.6.0",
4
- "about": "Send a synthetic sign-in email through the official SDK and inspect the retained message and local inbox after restart. Advance the frozen World clock to settle synthetic delivery before retained-state inspection.",
4
+ "about": "Send a synthetic sign-in email through the official SDK and inspect the retained message after restart. Advance the frozen World clock to settle synthetic delivery before retained-state inspection.",
5
5
  "files": {
6
6
  "package.json": "{\n \"name\": \"resend-installed-customer\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"resend\": \"6.6.0\"\n }\n}\n",
7
7
  ".env.example": "RESEND_API_KEY=\n",
8
- "inspect-email.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync } from 'node:fs';\nimport { Resend } from 'resend';\n\nassert.ok(process.env.VOLTER_WORLD, 'run this script through the World');\nconst { id } = JSON.parse(readFileSync('last-email.json', 'utf8'));\nconst resend = new Resend(process.env.RESEND_API_KEY);\nconst saved = await resend.emails.get(id);\nassert.equal(saved.error, null);\nassert.equal(saved.data.last_event, 'delivered');\nconst response = await fetch(`${process.env.RESEND_TWIN_URL}/_twin/mail?to=owner%40world.test`);\nassert.equal(response.status, 200);\nconst inbox = await response.json();\nconst email = inbox.mail.find((message) => message.id === id);\nassert.ok(email, 'the delivered message must be in the local inbox');\nassert.equal(email.subject, 'Your local sign-in code');\nassert.match(email.text, /123456/);\nassert.match(email.html, /<strong>123456<\\/strong>/);\nconsole.log('local inbox contains the delivered email and sign-in code');\n",
8
+ "inspect-email.mjs": "import assert from 'node:assert/strict';\nimport { readFileSync } from 'node:fs';\nimport { Resend } from 'resend';\n\nassert.ok(process.env.VOLTER_WORLD, 'run this script through the World');\nconst { id } = JSON.parse(readFileSync('last-email.json', 'utf8'));\nconst resend = new Resend(process.env.RESEND_API_KEY);\nconst saved = await resend.emails.get(id);\nassert.equal(saved.error, null);\nassert.equal(saved.data.last_event, 'delivered');\nassert.equal(saved.data.subject, 'Your local sign-in code');\nassert.match(saved.data.text, /123456/);\nassert.match(saved.data.html, /<strong>123456<\\/strong>/);\nconsole.log('the retained email reads back with its sign-in code');\n",
9
9
  "send-email.mjs": "import assert from 'node:assert/strict';\nimport { writeFileSync } from 'node:fs';\nimport { Resend } from 'resend';\n\nassert.ok(process.env.VOLTER_WORLD, 'run this script through the World');\nconst resend = new Resend(process.env.RESEND_API_KEY);\nconst email = {\n from: 'Example app <onboarding@resend.dev>',\n to: ['owner@world.test'],\n subject: 'Your local sign-in code',\n text: 'Your synthetic sign-in code is 123456.',\n html: '<p>Your synthetic sign-in code is <strong>123456</strong>.</p>'\n};\nconst sent = await resend.emails.send(email);\nassert.equal(sent.error, null);\nassert.ok(sent.data.id);\nconst saved = await resend.emails.get(sent.data.id);\nassert.equal(saved.error, null);\nassert.equal(saved.data.id, sent.data.id);\nassert.equal(saved.data.subject, email.subject);\nassert.equal(saved.data.text, email.text);\nassert.deepEqual(saved.data.to, email.to);\nwriteFileSync('last-email.json', JSON.stringify({ id: sent.data.id }) + '\\n');\nconsole.log('email sent and read back locally');\n"
10
10
  },
11
11
  "run": [
@@ -6,13 +6,10 @@ export type ConformanceResult = {
6
6
  note?: string;
7
7
  };
8
8
  /** The files conformance reads from a unit: its manifest, its spec's record, its vendor's life and its decision table
9
- * (a lane's journeys are its own `journeys/` or else its vendor's). A release publishes each (published()), and a
10
- * pack's standing counts it in the form only when every unit holds them (twin-world's scripts/pack-standing.ts, by
11
- * unitFilesMissing): the one list of both. */
9
+ * (a lane's journeys are its own `journeys/` or else its vendor's). A release publishes each (published()). */
12
10
  export declare const UNIT_FILES: readonly ["src/manifest.ts", "spec/SOURCE.md", "journeys/customer-life.json", "journeys/decisions.json"];
13
11
  /** The published package must carry every conformance input its units hold, including lanes. */
14
12
  export declare function unpublishedUnitFiles(unit: string): string[];
15
- export declare function unitFilesMissing(unit: string): string[];
16
13
  type Owners = Record<string, string>;
17
14
  type Decision = {
18
15
  operation: string;
@@ -64,9 +64,7 @@ async function credentialFields(server, door, host) {
64
64
  return { values: fields, outputs };
65
65
  }
66
66
  /** The files conformance reads from a unit: its manifest, its spec's record, its vendor's life and its decision table
67
- * (a lane's journeys are its own `journeys/` or else its vendor's). A release publishes each (published()), and a
68
- * pack's standing counts it in the form only when every unit holds them (twin-world's scripts/pack-standing.ts, by
69
- * unitFilesMissing): the one list of both. */
67
+ * (a lane's journeys are its own `journeys/` or else its vendor's). A release publishes each (published()). */
70
68
  export const UNIT_FILES = ['src/manifest.ts', 'spec/SOURCE.md', 'journeys/customer-life.json', 'journeys/decisions.json'];
71
69
  /** The published package must carry every conformance input its units hold, including lanes. */
72
70
  export function unpublishedUnitFiles(unit) {
@@ -80,8 +78,6 @@ export function unpublishedUnitFiles(unit) {
80
78
  return !patterns.some((p) => !p.exclude && matches(p.pattern)) || patterns.some((p) => p.exclude && matches(p.pattern));
81
79
  }).map((f) => `${f} is absent from package.json files (conformance reads it)`);
82
80
  }
83
- /** Each of UNIT_FILES a unit lacks where conformance reads it: the manifest of every unit, the life at its vendor's root
84
- * (lifeServed), the spec's record and the decision table of a unit with a spec (decided()). */
85
81
  const trackedJourneySources = new Map();
86
82
  /** Table ownership follows one index snapshot per checkout/run. */
87
83
  function hasJourneySource(unit) {
@@ -117,17 +113,6 @@ function hasJourneySource(unit) {
117
113
  const prefix = relative(checkout, dir).replaceAll('\\', '/') + '/';
118
114
  return source.some(path => path.startsWith(prefix));
119
115
  }
120
- export function unitFilesMissing(unit) {
121
- const vendor = existsSync(join(unit, 'package.json')) ? unit : dirname(unit);
122
- const spec = hasOwnSurface(unit);
123
- const at = {
124
- 'src/manifest.ts': unit,
125
- 'spec/SOURCE.md': spec ? unit : undefined,
126
- 'journeys/customer-life.json': vendor,
127
- 'journeys/decisions.json': spec ? (hasJourneySource(unit) ? unit : vendor) : undefined,
128
- };
129
- return UNIT_FILES.filter((f) => at[f] !== undefined && !existsSync(join(at[f], f))).map((f) => `${relative(unit, join(at[f], f))} is missing (conformance reads it)`);
130
- }
131
116
  /** A unit's fetch export: a pack's `create<Vendor>Fetch`, a lane's `create<Lane>LaneFetch`. */
132
117
  const fetchName = (dir) => (existsSync(join(dir, 'package.json')) ? `create${pascal(basename(dir))}Fetch` : `create${pascal(basename(dir))}LaneFetch`);
133
118
  const manifestOf = async (unit) => (await import(__rewriteRelativeImportExtension(join(unit, 'src', 'manifest.ts')))).manifest;
@@ -273,7 +258,7 @@ async function cited(pack) {
273
258
  for (const [url, quotes] of await citations(unit)) {
274
259
  const r = record[url];
275
260
  if (!r) {
276
- out.push(`${nameOf(pack, unit)}: ${url} is cited and not recorded (bun <twin-world>/scripts/check-sources.ts ${nameOf(pack, unit)})`);
261
+ out.push(`${nameOf(pack, unit)}: ${url} is cited and not recorded (twin-standard check-sources ${nameOf(pack, unit)})`);
277
262
  continue;
278
263
  }
279
264
  if (!sourceHeld(url, r))
@@ -897,8 +882,8 @@ async function clientCases(pack, scratch, consumer) {
897
882
  Object.assign(issued, (await credentialFields(server, door, host)).outputs);
898
883
  }
899
884
  const job = join(scratch, 'client-job.json');
900
- // a release carries its facts (generated/pack-facts.json, `twin-standard facts`); a source checkout does not, so its
901
- // facts are compiled here, as that command compiles them, for the client the case runs
885
+ // a pack carries its facts (generated/pack-facts.json, `twin-standard facts`), in source and release alike; one that
886
+ // has none yet has them compiled here, as that command compiles them, for the client the case runs
902
887
  let packFacts = join(pack, 'generated', 'pack-facts.json');
903
888
  if (!existsSync(packFacts)) {
904
889
  const { compilePackFacts, renderPackFacts } = await import("./pack-facts.js");
@@ -25,7 +25,7 @@ export declare function brief(unit: string): Promise<string>;
25
25
  export declare function packIndexFile(dir: string, vendor: string): string;
26
26
  /** A pack's `src/server.ts` (a fixed file), the kernel's serve seam around its fetch, naming only what its unit has so
27
27
  * it typechecks and a bundler follows every import: the plain seam (serveHttp, which takes the sockets a fetch carries
28
- * itself: "Other wires"), or, for a unit whose spec is a proto, the gRPC seam over the schema derive-pack generated
28
+ * itself: "Other wires"), or, for a unit whose spec is a proto, the gRPC seam over the schema the derivation generated
29
29
  * (src/generated/proto.gen.json, imported by its literal path). `--init` writes the plain one, `--index` the gRPC one once
30
30
  * the unit's proto is derived. */
31
31
  export declare function serverFile(vendor: string, grpc: boolean, wire?: boolean, live?: boolean): string;
@@ -10,8 +10,9 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
10
10
  // create-pack — the files of a Protocol 3 pack that nobody should write (the board's `create-pack` card;
11
11
  // docs/contributing/architecture.md, "Creating a pack"), and the brief an author writes the rest from.
12
12
  //
13
- // bun scripts/create-pack.ts <dir> --init <vendor> write every fixed file of a new pack that does not exist yet
14
- // bun scripts/create-pack.ts <dir> --init <vendor> --lanes a,b
13
+ // twin-standard create <dir> --init <vendor> --package <@scope/name>
14
+ // write every fixed file of a new pack that does not exist yet
15
+ // twin-standard create <dir> --init <vendor> --package <@scope/name> --lanes a,b
15
16
  // the same for a pack of lanes, one per API of the vendor, each
16
17
  // derived from its own spec (<dir>/<lane>/spec): each lane's
17
18
  // manifest, fetch, index and semantics, and the pack's server
@@ -20,11 +21,11 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
20
21
  // index}.ts, src/semantics/{states,shared,doors}.ts,
21
22
  // journeys/{demand,first-use}.json): the author fills the manifest's
22
23
  // vendor facts, the descriptor's hosts and the families
23
- // bun scripts/create-pack.ts <unit> --index write src/semantics/index.ts, the handler map, and src/fetch.ts from the
24
+ // twin-standard create <unit> --index write src/semantics/index.ts, the handler map, and src/fetch.ts from the
24
25
  // families' files (every exported function, by its name)
25
- // bun scripts/create-pack.ts <unit> --index --building the same during construction; unfinished operations stay gaps,
26
+ // twin-standard create <unit> --index --building the same during construction; unfinished operations stay gaps,
26
27
  // and implemented operations must match their decisions
27
- // bun scripts/create-pack.ts <unit> --brief [--out f] the author's brief: every operation the derived core does not
28
+ // twin-standard create <unit> --brief [--out f] the author's brief: every operation the derived core does not
28
29
  // serve and no handler answers yet, by family, with what the
29
30
  // vendored spec says of it (summary, description, parameters,
30
31
  // the answers it documents and their examples), so a handler
@@ -75,7 +76,7 @@ export function handlerIndex(dir) {
75
76
  // an index written before the derive has no operations to map, and every served call would fall to the gap (404): refuse
76
77
  // it rather than write an empty map (2026-09-30: six packs committed so)
77
78
  if (!existsSync(surfacePath) && fams.length)
78
- throw new Error(`${dir}: no src/generated/surface.gen.json yet; derive the unit (scripts/derive-pack.ts) before --index`);
79
+ throw new Error(`${dir}: no src/generated/surface.gen.json yet; derive the unit (twin-standard derive) before --index`);
79
80
  const where = new Map(fams.flatMap((f) => f.handlers.map((h) => [h, f.family])));
80
81
  const named = new Set([...new Set(ids)].map(handlerName));
81
82
  const stray = [...where.keys()].filter((h) => !named.has(h));
@@ -278,7 +279,7 @@ export async function brief(unit) {
278
279
  const s = spec.get(o.id);
279
280
  lines.push(`### ${o.id}${unmodeled.has(o.id) ? ' (unmodeled)' : ''}`, '', `\`${o.method.toUpperCase()} ${o.path}\` — ${o.class}${s?.summary ? `: ${oneLine(s.summary)}` : ''}`);
280
281
  // the citation a handler carries, ready to paste: by operationId where the spec names one, else by its JSON pointer,
281
- // quoting the spec's own words (derive-pack refuses a quote the spec does not hold)
282
+ // quoting the spec's own words (the derivation refuses a quote the spec does not hold)
282
283
  const words = oneLine(s?.summary ?? s?.description ?? '').split(/(?<=\.)\s/)[0].replace(/"/g, '\\"');
283
284
  const cite = s && s.operationId === o.id ? `spec:${o.id}` : `spec:/paths/${o.path.replace(/~/g, '~0').replace(/\//g, '~1')}/${o.method.toLowerCase()}`;
284
285
  if (words)
@@ -343,7 +344,7 @@ export function packIndexFile(dir, vendor) {
343
344
  }
344
345
  /** A pack's `src/server.ts` (a fixed file), the kernel's serve seam around its fetch, naming only what its unit has so
345
346
  * it typechecks and a bundler follows every import: the plain seam (serveHttp, which takes the sockets a fetch carries
346
- * itself: "Other wires"), or, for a unit whose spec is a proto, the gRPC seam over the schema derive-pack generated
347
+ * itself: "Other wires"), or, for a unit whose spec is a proto, the gRPC seam over the schema the derivation generated
347
348
  * (src/generated/proto.gen.json, imported by its literal path). `--init` writes the plain one, `--index` the gRPC one once
348
349
  * the unit's proto is derived. */
349
350
  export function serverFile(vendor, grpc, wire = false, live = false) {
@@ -443,7 +444,7 @@ export function initFiles(vendor) {
443
444
  'src/semantics/states.ts': `// ${vendor}'s state machines and state rulings, each transition cited (architecture, "State").\nexport const states = {};\n`,
444
445
  'src/semantics/shared.ts': `// What every family of ${vendor} shares: its stored shapes, who is calling, and the vendor's answers.\nimport type { HandlerContext } from '@volter/world-core';\n\nexport type Row = Record<string, unknown>;\nexport type { HandlerContext };\n`,
445
446
  'src/semantics/doors.ts': `// The World's doors (architecture, "Doors, screens and the gap"): what the vendor's own pages do that its API does\n// not, each declared in the manifest's \`doors\` (its id, method and path under \`/_twin/\`) and answered here by the\n// export its id names, over the contract's context.\nimport type { HandlerContext } from '@volter/world-core';\n\nexport type { HandlerContext };\n`,
446
- 'src/manifest.ts': `// ${vendor}'s manifest: the vendor facts its spec does not carry (architecture, "Protocol 3"). The surface is generated\n// (./generated/surface.gen.json, from ../spec by derive-pack). Every line marked FILL is a vendor fact to state from\n// the vendor's pages, cited.\nimport type { DerivedManifest } from '@volter/world-core';\n\nexport const manifest: DerivedManifest = {\n vendor: '${vendor}',\n service: '${vendor}',\n body: { json: 'always' },\n ids: { template: '{uuid}' }, // FILL: the vendor's id form\n time: 'iso', // FILL: iso, unix or unix-ms\n error: { error: { message: '{message}', code: '{code}' } }, // FILL: the vendor's error body\n readOnly: { status: 403, message: 'This twin was started read-only; writes are refused.' }, // FILL: the vendor's refusal\n notFound: { status: 404, message: 'Not found' }, // FILL: the vendor's not-found\n list: { style: 'envelope', envelope: { data: '{data}' }, limit: { param: 'limit', default: 20, max: 100 } }, // FILL: its paging\n deleted: {},\n resources: {}, // FILL: the resources the core serves (plain create, read, update, delete, list)\n discovery: { twinOf: 'FILL: what the twin is of', stores: 'FILL: what it keeps' },\n // the descriptor, as data (twin-world's architecture, "The descriptor"): the pack registers packOf(manifest)\n descriptor: {\n protocol: '3',\n transport: 'rest',\n archetype: 'crud',\n bin: 'world-${vendor}',\n resources: [], // FILL: the stored types\n specSource: 'FILL: the vendored spec (spec/SOURCE.md)',\n description: 'FILL: one line',\n adoption: { sdks: [], envStems: [] }, // FILL: its npm clients, and each credential variable's stem (TRIPO for TRIPO_API_KEY: the suffix removed)\n hosts: [], // FILL: the vendor's hosts\n endpointEnvNone: 'FILL: the SDK\\'s base-URL variable (endpointEnv) or why none',\n },\n};\n`,
447
+ 'src/manifest.ts': `// ${vendor}'s manifest: the vendor facts its spec does not carry (architecture, "Protocol 3"). The surface is generated\n// (./generated/surface.gen.json, from ../spec by twin-standard derive). Every line marked FILL is a vendor fact to state from\n// the vendor's pages, cited.\nimport type { DerivedManifest } from '@volter/world-core';\n\nexport const manifest: DerivedManifest = {\n vendor: '${vendor}',\n service: '${vendor}',\n body: { json: 'always' },\n ids: { template: '{uuid}' }, // FILL: the vendor's id form\n time: 'iso', // FILL: iso, unix or unix-ms\n error: { error: { message: '{message}', code: '{code}' } }, // FILL: the vendor's error body\n readOnly: { status: 403, message: 'This twin was started read-only; writes are refused.' }, // FILL: the vendor's refusal\n notFound: { status: 404, message: 'Not found' }, // FILL: the vendor's not-found\n list: { style: 'envelope', envelope: { data: '{data}' }, limit: { param: 'limit', default: 20, max: 100 } }, // FILL: its paging\n deleted: {},\n resources: {}, // FILL: the resources the core serves (plain create, read, update, delete, list)\n discovery: { twinOf: 'FILL: what the twin is of', stores: 'FILL: what it keeps' },\n // the descriptor, as data (twin-world's architecture, "The descriptor"): the pack registers packOf(manifest)\n descriptor: {\n protocol: '3',\n transport: 'rest',\n archetype: 'crud',\n bin: 'world-${vendor}',\n resources: [], // FILL: the stored types\n specSource: 'FILL: the vendored spec (spec/SOURCE.md)',\n description: 'FILL: one line',\n adoption: { sdks: [], envStems: [] }, // FILL: its npm clients, and each credential variable's stem (TRIPO for TRIPO_API_KEY: the suffix removed)\n hosts: [], // FILL: the vendor's hosts\n endpointEnvNone: 'FILL: the SDK\\'s base-URL variable (endpointEnv) or why none',\n },\n};\n`,
447
448
  'src/server.ts': serverFile(vendor, false),
448
449
  'src/cli.ts': cliFile(vendor),
449
450
  'src/index.ts': `// @volter/twin-${vendor} — the ${vendor} twin (Protocol 3). A fixed file: the descriptor is the manifest's.\nimport { packOf, registerPack } from '@volter/world-core';\nimport { manifest } from './manifest.ts';\n\nexport { create${Name}Fetch } from './fetch.ts';\nexport { create${Name}TwinServer } from './server.ts';\nexport { manifest };\n\n// The descriptor: twin-world's architecture, "The descriptor"; declared in manifest.ts.\nexport const pack = registerPack(packOf(manifest));\n`,
@@ -522,7 +523,7 @@ export async function fixedFiles(dir) {
522
523
  throw new Error('Pack manifest must declare its vendor identity independently of the npm package name');
523
524
  files['src/index.ts'] = packIndexFile(dir, vendor);
524
525
  if (!existsSync(join(dir, 'src', 'stream.ts'))) {
525
- // a unit whose spec is a proto (derive-pack generated its schema) is served over gRPC: its serve seam in that form
526
+ // a unit whose spec is a proto (the derivation generated its schema) is served over gRPC: its serve seam in that form
526
527
  const lanesOnly = !hasOwnSurface(dir) && readdirSync(dir).some((n) => existsSync(join(dir, n, 'src', 'manifest.ts')));
527
528
  const grpc = !lanesOnly && existsSync(join(dir, 'src', 'generated', 'proto.gen.json'));
528
529
  // a unit that takes broadcasts over RTMP (its manifest's `live`) has the live forms --index writes, so they reproduce
@@ -535,7 +536,7 @@ export async function fixedFiles(dir) {
535
536
  export async function createPack(args) {
536
537
  const [unit, ...rest] = args;
537
538
  if (!unit || (!rest.includes('--index') && !rest.includes('--brief') && !rest.includes('--init'))) {
538
- console.error('usage: bun scripts/create-pack.ts <dir> --init <vendor> | <unit> --index [--building] | --brief [--out <file>]');
539
+ console.error('usage: twin-standard create <dir> --init <vendor> --package <@scope/name> | <unit> --index [--building] | --brief [--out <file>]');
539
540
  process.exit(2);
540
541
  }
541
542
  if (rest.includes('--building') && (!rest.includes('--index') || rest.includes('--init') || rest.includes('--brief'))) {
@@ -642,7 +643,7 @@ export async function createPack(args) {
642
643
  writeFileSync(join(dir, 'tsconfig.json'), TSCONFIG);
643
644
  console.log(`create-pack: wrote ${join(dir, 'tsconfig.json')}`);
644
645
  }
645
- // a unit whose spec is a proto (derive-pack generated its schema) is served over gRPC: its serve seam in that form,
646
+ // a unit whose spec is a proto (the derivation generated its schema) is served over gRPC: its serve seam in that form,
646
647
  // the one form a unit takes after --init (a server.ts of a wire of the pack's own, SMTP's, is never written over)
647
648
  if (!lanesOnly && existsSync(join(dir, 'src', 'generated', 'proto.gen.json'))) {
648
649
  const wire = existsSync(join(dir, 'src', 'stream.ts'));
@@ -13,7 +13,7 @@ import { parseExactJson, exactInteger } from '@volter/world-core/exact-json';
13
13
  // vendored spec (`<pack>/spec/openapi.json[.gz]`), builds the spec IR (./spec-ir.ts) and writes the pack's
14
14
  // `src/generated/`. Deterministic: a second run over the same spec writes the same bytes. Never hand-edit what it writes.
15
15
  //
16
- // Usage: twin-standard derive <pack dir> [--out <dir>] (twin-world: bun scripts/derive-pack.ts <vendor>)
16
+ // Usage: twin-standard derive <pack dir> [--out <dir>]
17
17
  import { parse as parseYaml } from 'yaml';
18
18
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
19
19
  import { basename, join } from 'node:path';
@@ -47,7 +47,7 @@ const PKG = unitAt(vendor).dir;
47
47
  const rfc = existsSync(join(PKG, 'spec')) ? readdirSync(join(PKG, 'spec')).find((f) => /^rfc\d+\.txt$/.test(f)) : undefined;
48
48
  const specPath = ['openapi.json.gz', 'openapi.json', 'openapi.yaml.gz', 'openapi.yaml', 'smithy.json.gz', 'smithy.json', 'discovery.json.gz', 'discovery.json', ...(rfc ? [rfc] : []), 'openapi', 'proto', 'commands', 'command-builders.json', 'client-ops.json'].map((f) => join(PKG, 'spec', f)).find((p) => existsSync(p));
49
49
  if (!specPath) {
50
- console.error(`derive-pack: no spec at ${join(PKG, 'spec')}/openapi.{json,yaml}[.gz], smithy.json[.gz], rfcNNNN.txt, proto/, commands/, command-builders.json or client-ops.json`);
50
+ console.error(`derive: no spec at ${join(PKG, 'spec')}/openapi.{json,yaml}[.gz], smithy.json[.gz], rfcNNNN.txt, proto/, commands/, command-builders.json or client-ops.json`);
51
51
  process.exit(SOURCE_REFUSAL);
52
52
  }
53
53
  const rpcService = basename(specPath) === 'proto';
@@ -343,7 +343,7 @@ if (existsSync(manifestPath)) {
343
343
  }
344
344
  // a resource's refresh scope ("The real-system adapters", What a pack declares) names the list that enumerates it or
345
345
  // its retrieve, or says why the vendor offers no read-back; whether every stored resource declares one is
346
- // pack-standing's report, not this build's
346
+ // not this build's to decide
347
347
  // (a resource the spec names is read by its own list or retrieve; one the manifest names apart from the spec's, an RPC
348
348
  // vendor's, by the list or read the scope names, with `items` where the answer holds them when the spec does not say)
349
349
  const specNamed = new Set(ir.resources.map((r) => r.name));
@@ -1,5 +1,5 @@
1
1
  export { grade, STANDARDS, type CriterionGrade, type GradeOptions, type StandardGrade } from './grade.js';
2
- export { conformance, decisionTableProblems, type ConformanceResult, UNIT_FILES, unitFilesMissing } from './conformance.js';
2
+ export { conformance, decisionTableProblems, type ConformanceResult, UNIT_FILES } from './conformance.js';
3
3
  export { laneRootFailures, p3Gate, unitsOf } from './gate.js';
4
4
  export { conformPublished, gatePublished, vendorOfPackage, type PublishedGate } from './published.js';
5
5
  export { handlerName, protocol3, PLANNED, withCheckoutFiles } from './protocol-3.js';
package/dist/src/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  // of a submission — judges by the same standard at the version it pins. Changing a criterion is a release of this
5
5
  // package: a criterion's id never changes meaning, a changed criterion takes a new id and a new standard version.
6
6
  export { grade, STANDARDS } from "./grade.js";
7
- export { conformance, decisionTableProblems, UNIT_FILES, unitFilesMissing } from "./conformance.js";
7
+ export { conformance, decisionTableProblems, UNIT_FILES } from "./conformance.js";
8
8
  export { laneRootFailures, p3Gate, unitsOf } from "./gate.js";
9
9
  export { conformPublished, gatePublished, vendorOfPackage } from "./published.js";
10
10
  export { handlerName, protocol3, PLANNED, withCheckoutFiles } from "./protocol-3.js";
@@ -29,6 +29,7 @@ export type PackFacts = {
29
29
  demandPathPattern?: string | false;
30
30
  key?: string;
31
31
  exclude?: true;
32
+ basic?: string;
32
33
  }>;
33
34
  hostsNone?: string;
34
35
  hostsClaimed?: {
@@ -104,6 +105,8 @@ export type PackFacts = {
104
105
  scheme?: string;
105
106
  note: string;
106
107
  }>;
108
+ /** The vendor's own requests a World's generated seed makes (see TwinPack.seed). */
109
+ seed?: TwinPack['seed'];
107
110
  /** DERIVED, never declared: the pack's `create<Name>TwinServer` factory export — the
108
111
  * `({port,root,readOnly}) => {port,stop}` contract the colocated host mounts
109
112
  * (world-runtime/src/host.ts). Read off the module's own exports because the name is not
@@ -42,6 +42,8 @@ function validateHostRules(vendor, rules, vendors, claimedKeys, worldIds) {
42
42
  }
43
43
  if (rule.exclude !== undefined && rule.exclude !== true)
44
44
  throw new Error(`pack-facts: ${vendor} host rule ${JSON.stringify(rule)} — exclude is \`true\` or absent, never a falsy flag`);
45
+ if (rule.basic !== undefined && (typeof rule.basic !== 'string' || !/^[^:\s]+$/.test(rule.basic) || rule.exclude))
46
+ throw new Error(`pack-facts: ${vendor} host rule ${JSON.stringify(rule)} — basic names a user (no colon, no space) on an included host`);
45
47
  const key = rule.key ?? vendor;
46
48
  // A foreign key is a WORLD identity too: `volter-world init` emits <KEY>_TWIN_URL only for the
47
49
  // ids in adoption.worldIds (covers.ts injectorVendorKeysFor), so a key not listed there would
@@ -230,6 +232,39 @@ export async function compilePackFacts(dirs) {
230
232
  }
231
233
  facts.sidePorts = pack.sidePorts;
232
234
  }
235
+ if (pack.seed !== undefined) {
236
+ // ADR 0033 §3: one door per kind of fact, each the vendor's own request at its own host; only a domain's DNS record
237
+ // is a `/_twin/` stand-in
238
+ const seed = pack.seed;
239
+ const door = (value, what, standIn = false) => {
240
+ let url;
241
+ try {
242
+ url = new URL(String(value));
243
+ }
244
+ catch {
245
+ throw new Error(`pack-facts: ${vendor} seed ${what} "${String(value)}" is not a URL`);
246
+ }
247
+ if (url.protocol !== 'https:')
248
+ throw new Error(`pack-facts: ${vendor} seed ${what} is the vendor's own https request`);
249
+ if (!standIn && url.pathname.startsWith('/_twin/'))
250
+ throw new Error(`pack-facts: ${vendor} seed ${what} is the vendor's own request, never a /_twin/ door`);
251
+ };
252
+ if (!seed || typeof seed !== 'object' || Array.isArray(seed) || Object.keys(seed).some((k) => k !== 'signUp' && k !== 'domain'))
253
+ throw new Error(`pack-facts: ${vendor} seed is { signUp?, domain? }`);
254
+ if (seed.signUp !== undefined)
255
+ door(seed.signUp, 'signUp');
256
+ if (seed.domain !== undefined) {
257
+ const domain = seed.domain;
258
+ if (!domain || typeof domain !== 'object' || Array.isArray(domain) || Object.keys(domain).sort().join() !== 'add,record,settles,verify')
259
+ throw new Error(`pack-facts: ${vendor} seed.domain is { add, record, verify, settles }`);
260
+ door(domain.add, 'domain.add');
261
+ door(domain.verify, 'domain.verify');
262
+ door(domain.record, 'domain.record', true);
263
+ if (typeof domain.settles !== 'string' || !/^\d+[smhd]$/.test(domain.settles))
264
+ throw new Error(`pack-facts: ${vendor} seed.domain.settles is a World-clock time (10m)`);
265
+ }
266
+ facts.seed = pack.seed;
267
+ }
233
268
  // The serve factory is DERIVED from the module's exports (see PackFacts.serveExport);
234
269
  // a pack exporting SEVERAL factories must declare which one `cli.ts serve` boots — the
235
270
  // exports alone cannot reveal that judgment (linear defaults to its DERIVED server).
@@ -250,7 +285,7 @@ export async function compilePackFacts(dirs) {
250
285
  packs[vendor] = facts;
251
286
  }
252
287
  return {
253
- '//': 'GENERATED by scripts/pack-facts.ts — current pack descriptors and explicit world-runtime server backings; no prior-artifact entries are retained.',
288
+ '//': 'GENERATED by twin-standard facts from the pack descriptor; no prior-artifact entries are retained.',
254
289
  packs: sortObject(packs),
255
290
  undeclared,
256
291
  };
@@ -191,7 +191,7 @@ function noReport(unit) {
191
191
  /** An operation's family: the first segment of its path after a version (`/v1/organizations/{id}` is `organizations`), a
192
192
  * dotted RPC method's first part (`chat.postMessage` is `chat`), a line command's name (architecture, "Pack layout"). */
193
193
  function familyOf(path) {
194
- // the interim rule ("What an author writes"), until derive-pack writes the spec's own grouping on each operation
194
+ // the interim rule ("What an author writes"), until the derivation writes the spec's own grouping on each operation
195
195
  const segs = path.split('/').filter((x) => x && !/^v?\d+(\.\d+)?$|^\d{4}-\d{2}-\d{2}$/.test(x) && !x.startsWith('{'));
196
196
  if (!segs.length)
197
197
  return 'operations'; // named in a header: every path is `/`
@@ -290,7 +290,7 @@ const criteria = [
290
290
  },
291
291
  {
292
292
  id: 'derived-reproducible', section: 'form',
293
- asks: 'derive-pack regenerates src/generated/ byte for byte',
293
+ asks: 'twin-standard derive regenerates src/generated/ byte for byte',
294
294
  check(unit) {
295
295
  const gen = join(unit.dir, 'src', 'generated');
296
296
  if (!existsSync(gen))
@@ -310,10 +310,10 @@ const criteria = [
310
310
  // a standing written from one checkout reads the same from any other
311
311
  if (run.status === null || run.signal !== null || run.error)
312
312
  return { pass: false, cacheable: false,
313
- reason: `derive-pack interrupted: status=${run.status} signal=${run.signal} error=${run.error?.message ?? ''}` };
313
+ reason: `derive interrupted: status=${run.status} signal=${run.signal} error=${run.error?.message ?? ''}` };
314
314
  if (run.status !== 0)
315
- return { ...fail(`derive-pack refused: ${String(run.stderr || run.stdout).split(unit.dir).join('.').split(tmp).join('<out>').trim().split('\n').slice(-2).join(' ').slice(0, 200)}`), cacheable: run.status === 2 };
316
- return changed.length ? fail(`derive-pack writes differently: ${changed.slice(0, 5).join(', ')}${changed.length > 5 ? ` and ${changed.length - 5} more` : ''}`) : pass(`${filesUnder(gen).length} files reproduced`);
315
+ return { ...fail(`derive refused: ${String(run.stderr || run.stdout).split(unit.dir).join('.').split(tmp).join('<out>').trim().split('\n').slice(-2).join(' ').slice(0, 200)}`), cacheable: run.status === 2 };
316
+ return changed.length ? fail(`derive writes differently: ${changed.slice(0, 5).join(', ')}${changed.length > 5 ? ` and ${changed.length - 5} more` : ''}`) : pass(`${filesUnder(gen).length} files reproduced`);
317
317
  },
318
318
  },
319
319
  {
@@ -6,7 +6,7 @@
6
6
  // `spec/`, Creating a pack, step 2): its method, its URL as the client
7
7
  // builds it (a label is the Python expression the client interpolates), the query keys it sends (literal, or the keys
8
8
  // of the dict it urlencodes) and its body's keys, each typed by the client's own annotation of the value (`null`
9
- // where the client does not say). A spec patch corrects the table as it corrects a JSON spec (derive-pack): what the
9
+ // where the client does not say). A spec patch corrects the table as it corrects a JSON spec (twin-standard derive): what the
10
10
  // client builds as a raw string (a token's scopes) comes from the vendor's reference page that way.
11
11
  //
12
12
  // The calls at one method and path are one operation, their query and body keys together. The client says nothing
@@ -3,7 +3,7 @@
3
3
  // its group, the version it arrived in, its arity, its arguments, its flags and its reply's schema); a pack whose wire
4
4
  // carries Redis commands (Upstash's REST API: a command and its arguments in the path or the body) vendors the files of
5
5
  // the commands its vendor serves and derives its command surface from them, as a line protocol's surface is its RFC's
6
- // command table (spec-ir-lines.ts). A spec patch corrects the data as it corrects a JSON spec (derive-pack).
6
+ // command table (spec-ir-lines.ts). A spec patch corrects the data as it corrects a JSON spec (twin-standard derive).
7
7
  function argumentOf(a) {
8
8
  return {
9
9
  name: String(a.name),
@@ -1,6 +1,6 @@
1
1
  // A line protocol's spec as data: the commands a client sends and the replies each may be answered,
2
2
  // read from the RFC's own table of them. The IR a byte-stream pack derives its surface from, as an HTTP
3
- // pack derives its from an OpenAPI document; a spec patch corrects it the same way (derive-pack).
3
+ // pack derives its from an OpenAPI document; a spec patch corrects it the same way (twin-standard derive).
4
4
  //
5
5
  // SMTP's table is RFC 5321 §4.3.2 "Command-Reply Sequences": each command, then its intermediate (I),
6
6
  // success (S) and error (E) codes, where `I: 354 -> data -> S: 250` says what answers the lines that
@@ -40,7 +40,7 @@ export type ProtoFile = {
40
40
  };
41
41
  /** One `.proto` file's declarations. */
42
42
  export declare function parseProto(path: string, text: string): ProtoFile;
43
- /** The vendored tree (path → text) as data, so a spec patch corrects it as it corrects a JSON spec (derive-pack). */
43
+ /** The vendored tree (path → text) as data, so a spec patch corrects it as it corrects a JSON spec (twin-standard derive). */
44
44
  export type ProtoSpec = {
45
45
  format: 'proto';
46
46
  files: ProtoFile[];
@@ -1,6 +1,6 @@
1
1
  // A pack's corrections to its vendor's spec (spec/patches.json): RFC 6902 operations (add, replace, remove, move, copy),
2
- // applied to the parsed spec so the vendored file stays the vendor's own bytes. derive-pack.ts applies them before the
3
- // IR; vendor-examples.ts reads the patched schemas, which are what the twin is derived from.
2
+ // applied to the parsed spec so the vendored file stays the vendor's own bytes. the derivation applies them before the
3
+ // IR; `twin-standard examples` reads the patched schemas, which are what the twin is derived from.
4
4
  /** Apply one patch to `doc` in place. */
5
5
  export function applySpecPatch(doc, p) {
6
6
  const at = (pointer) => {
@@ -3,8 +3,7 @@
3
3
  // runtime). The verdict names its judge and the authors; the grade refuses one whose judge is an author
4
4
  // (packages/twin-standard/src/verdict.ts). One judging per pack: the verdict stands through later changes.
5
5
  //
6
- // twin-standard judge-brief <vendor> --authors <author name>[,<agent>...] (from the pack repository's root; twin-world's
7
- // bun scripts/judge-brief.ts runs the same)
6
+ // twin-standard judge-brief <vendor> --authors <author name>[,<agent>...] (from the pack repository's root)
8
7
  import { attributionName } from "../verdict.js";
9
8
  import { createHash } from 'node:crypto';
10
9
  import { existsSync, readFileSync } from 'node:fs';
@@ -32,8 +32,8 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
32
32
  // A walk that fails, and a file in scope (the pack's src/ on disk, its sharing lanes' too) that declares code yet
33
33
  // measures no line, stop the measurement: neither is a file with nothing to reach.
34
34
  //
35
- // Usage: twin-standard coverage <vendor> [--write | --out <file>] [--prune] (from the pack repository's root; twin-world's
36
- // bun scripts/life-coverage.ts runs the same) (--prune removes the stale records) (--write keeps journeys/coverage.json)
35
+ // Usage: twin-standard coverage <vendor> [--write | --out <file>] [--prune] (from the pack repository's root)
36
+ // (--prune removes the stale records) (--write keeps journeys/coverage.json)
37
37
  import { spawnSync } from 'node:child_process';
38
38
  import ts from 'typescript';
39
39
  import { existsSync, mkdtempSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
@@ -1,8 +1,8 @@
1
1
  // Where the contributor's tools (walk, examples, coverage, judge-brief) find the pack they are given: a vendor's directory
2
2
  // under the pack repository they run from. A contributor runs them from their own repository's root (`twin-standard walk
3
- // <vendor>`), so that root is the working directory; twin-world's scripts, which find Volter's pack repository beside
4
- // their checkout, name it before loading a tool (setPacksRoot), and the kernel checkout a walk must measure
5
- // (setKernelCheckout). Each tool reads both once, when it loads.
3
+ // <vendor>`), so that root is the working directory; a tool that runs another in a process of its own (run-tool.ts)
4
+ // names it before loading the tool (setPacksRoot), with the kernel checkout a walk must measure (setKernelCheckout).
5
+ // Each tool reads both once, when it loads.
6
6
  import { join } from 'node:path';
7
7
  let packs = process.cwd();
8
8
  let kernel;
@@ -12,8 +12,7 @@
12
12
  // This is source-journey evidence, not installed readiness or pack completion. pack-done owns completion and consumes
13
13
  // this report alongside the exact artifact's installed customer assessment in the one final run.
14
14
  //
15
- // Usage: twin-standard walk <vendor> [--write] [--report <path>] (from the pack repository's root; twin-world's
16
- // bun scripts/score-pack.ts <vendor> runs the same)
15
+ // Usage: twin-standard walk <vendor> [--write] [--report <path>] (from the pack repository's root)
17
16
  // --write keeps journeys/score.json and journeys/coverage.json; --report writes the report and what it lacks for done
18
17
  // to <path> as JSON and changes nothing in the checkout
19
18
  import { parseExactJson } from '@volter/world-core/exact-json';
@@ -43,8 +43,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
43
43
  // read for. `--sweep` prints, without changing done, every actor field (creator, user, *_by, ...) no `equals` pins and every
44
44
  // list no expect closes: advice for fixing a ruling as a class (its hits include lists a pinned text already fixes).
45
45
  //
46
- // Usage: twin-standard examples <vendor> [--sweep] (from the pack repository's root; twin-world's
47
- // bun scripts/vendor-examples.ts <vendor> runs the same)
46
+ // Usage: twin-standard examples <vendor> [--sweep] (from the pack repository's root)
48
47
  import { parseExactJson, exactInteger, isExactIntegerValue } from '@volter/world-core/exact-json';
49
48
  import { hasOwnSurface } from "../lanes.js";
50
49
  import { archiveSource } from "../archive-source.js";
@@ -95,7 +94,7 @@ function answerKeys(output, published, sent, placeholder, rawBindings = false) {
95
94
  : value;
96
95
  return mapped(output);
97
96
  }
98
- /** The schemas the twin serves: the vendor's, with the pack's spec patches (spec/patches.json) applied as derive-pack
97
+ /** The schemas the twin serves: the vendor's, with the pack's spec patches (spec/patches.json) applied as the derivation
99
98
  * applies them. A sample is checked against what the twin is derived from; the published examples themselves stay the
100
99
  * vendor's bytes. */
101
100
  function served(pkg, doc) {
@@ -426,7 +425,7 @@ function fromSpec(pkg, lane, model) {
426
425
  }
427
426
  return out;
428
427
  }
429
- // a spec vendored as published or gzipped, as derive-pack reads it
428
+ // a spec vendored as published or gzipped, as the derivation reads it
430
429
  const spec = ['openapi.json.gz', 'openapi.json', 'openapi.yaml.gz', 'openapi.yaml', 'discovery.json.gz', 'discovery.json'].map((f) => join(pkg, 'spec', f)).find((p) => existsSync(p));
431
430
  // a Protocol Buffers service publishes no examples in its .proto files: its examples are its documentation's alone
432
431
  if (!spec && existsSync(join(pkg, 'spec', 'proto')))
@@ -442,7 +441,7 @@ function fromSpec(pkg, lane, model) {
442
441
  if (!spec && !documents)
443
442
  throw new Error(`${pkg}: no published-example reader for this spec yet`);
444
443
  const text = spec ? (spec.endsWith('.gz') ? gunzipSync(readFileSync(spec)) : readFileSync(spec)).toString('utf8') : '';
445
- // a Google API Discovery document publishes no examples; it is read as the OpenAPI document derive-pack reads it as,
444
+ // a Google API Discovery document publishes no examples; it is read as the OpenAPI document the derivation reads it as,
446
445
  // its patches applied to the Discovery document first (spec-ir-discovery.ts)
447
446
  const discovery = spec !== undefined && /discovery\.json(\.gz)?$/.test(spec);
448
447
  const docs = (documents ? Object.values(documents.documents) : [discovery ? discoveryToOpenAPI(parseExactJson(text)) : /\.yaml(\.gz)?$/.test(spec) ? parseExactJson(JSON.stringify(parseYaml(text, { intAsBigInt: true }), (_key, value) => typeof value === 'bigint' ? exactInteger(String(value)) : value)) : parseExactJson(text)]);
@@ -1,7 +1,7 @@
1
1
  // A JUDGE'S INDEPENDENCE (the grade's outline-judged and life-judged, the published examples' verdict): a verdict rules
2
2
  // only when it names its judge (`judge.agent`) and the authors of what it judges (`authors`), and the judge is none of
3
3
  // them. The dispatcher stamps author names consistently; a judge started independently
4
- // (scripts/judge-brief.ts prints its brief) names its reviewer role (`judge.name`). One judging per pack: the
4
+ // (`twin-standard judge-brief` prints its brief) names its reviewer role (`judge.name`). One judging per pack: the
5
5
  // verdict stands, and later changes to what it judged keep it (architecture, "Writing a life", Judge).
6
6
  /** Committed attribution names people or author roles, never execution identities. */
7
7
  export function attributionName(name) {
@@ -21,7 +21,7 @@ import { createRequire } from 'node:module';
21
21
  import { gzipSync } from 'node:zlib';
22
22
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
23
23
  import { join } from 'node:path';
24
- import { databaseSession, getActivePackAssets, getActiveWorldStore, LocalPackAssets, MemoryBlobStore, MemoryWorldStore, setActiveBlobStore, setActivePackAssets, setActiveWorldStore, setDeliveryObserver, setInProcessTwins, settleEventDeliveries, worldDoorMatcher, worldNow } from '@volter/world-core/runtime';
24
+ import { databaseSession, getActivePackAssets, getActiveWorldStore, LocalPackAssets, MemoryBlobStore, MemoryWorldStore, setActiveBlobStore, setActivePackAssets, setActiveWorldStore, setDeliveryObserver, setInProcessMailServers, setInProcessTwins, settleEventDeliveries, worldDoorMatcher, worldNow } from '@volter/world-core/runtime';
25
25
  import { createHostTable } from '@volter/world-core/host-routing';
26
26
  import packFactsDocument from '@volter/world-core/generated/pack-facts.json' with { type: 'json' };
27
27
  import { isMongo, isMysql, isResp, at, captureAt, echoFailures, expandFills, expectFailures, fill, fillJson, formBody, isGit, isLine, isSql, isSocket, isWait, jwtAuthorization, oauth1Authorization, presignedPath, sigv4Headers, waitMs } from "./journey-kit.js";
@@ -255,6 +255,21 @@ export async function walk(journey, root, collect, opts) {
255
255
  }
256
256
  companions.push({ vendor, keys, fetch: companion(root, { application }), databaseDoor: companion.managedDatabaseDoor });
257
257
  }
258
+ // a companion that receives mail (an SMTP side port: gmail's, gmail.com's MX) is the mail server ctx.mail reaches for
259
+ // the domains its host rules claim, on its byte-stream door in process over this walk's World, as a World reaches its
260
+ // listener: the life declares the provider of every address it mails
261
+ const mailServers = [];
262
+ for (const c of companions) {
263
+ const sides = walkFacts[c.vendor.split('/')[0]]?.sidePorts ?? [];
264
+ if (!sides.some((side) => side.scheme === 'smtp'))
265
+ continue;
266
+ const stream = await vendorStream(packsDir(), c.vendor, dependenciesDir());
267
+ if (!stream) {
268
+ collect.push({ step: '(setup)', beat: 'ADAPTER', detail: `the companion ${c.vendor} receives mail on an smtp side port and exports no create<Name>TwinStream` });
269
+ return {};
270
+ }
271
+ mailServers.push({ vendor: c.vendor, receives: (domain) => c.keys.some((key) => walkHosts[key](domain, '/')), stream: stream(root, { application }) });
272
+ }
258
273
  const eventFields = new Map();
259
274
  for (const vendor of [journey.vendor, ...companions.map((companion) => companion.vendor)]) {
260
275
  const directory = directoryFor(vendor);
@@ -1030,6 +1045,7 @@ export async function walk(journey, root, collect, opts) {
1030
1045
  ...companions.flatMap((c) => c.keys.map((key) => [key, c.fetch])),
1031
1046
  ...ownKeys.map((key) => [key, twin]),
1032
1047
  ]));
1048
+ const previousMailServers = setInProcessMailServers(mailServers);
1033
1049
  try {
1034
1050
  for (const step of journey.steps) {
1035
1051
  await settleEventDeliveries(root);
@@ -1343,6 +1359,7 @@ export async function walk(journey, root, collect, opts) {
1343
1359
  finally {
1344
1360
  setDeliveryObserver(previousObserver);
1345
1361
  setInProcessTwins(previousTwins);
1362
+ setInProcessMailServers(previousMailServers);
1346
1363
  try {
1347
1364
  if (sqlSession)
1348
1365
  await sqlSession.then((session) => session.end(), () => { });
@@ -127,7 +127,7 @@ export type JourneyStep = {
127
127
  * whose values the wire encodes (a psdb result's rows, base64 values sliced by per-column lengths) is asserted by
128
128
  * what it holds. Captures read the answer as it came. */
129
129
  view?: string;
130
- /** This step sends a vendor's published example, `<operation>#<title>` (scripts/vendor-examples.ts): its answer
130
+ /** This step sends a vendor's published example, `<operation>#<title>` (tools/vendor-examples.ts): its answer
131
131
  * must hold every key path of the example's answer with the same JSON type. */
132
132
  example?: string;
133
133
  /** Caller-chosen values of the example's named placeholders, compared literally; captures may fill them.
@@ -138,7 +138,7 @@ export type JourneyStep = {
138
138
  exampleDiffers?: Record<string, string>;
139
139
  /** A published body field this step leaves out (a dot path; `a[].b` in each item) → why: a rendered value naming an
140
140
  * object the World does not hold (a Git repository behind an integration). Only a field the request schema does not
141
- * require may be left out (scripts/vendor-examples.ts). */
141
+ * require may be left out (tools/vendor-examples.ts). */
142
142
  unsent?: Record<string, string>;
143
143
  /** answer paths whose value equals something the setup sent without the setup deciding it (a default the vendor applies
144
144
  * that coincides), each with the reason: `vendor-examples.ts --sweep` does not ask them asserted, and the judge reads the reason */