@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
@@ -44,6 +44,12 @@ async function serve(pack, options) {
44
44
  }
45
45
  throw error;
46
46
  }
47
+ // a raw-TCP pack's HTTP control seam is the side port its descriptor declares for HTTP (a mail relay's policy door),
48
+ // where the pack's factory names it by that side port's option
49
+ const declared = descriptor?.transport === 'raw-tcp' ? descriptor.sidePorts?.find((side) => (side.scheme ?? 'http') === 'http') : undefined;
50
+ const control = declared ? server[declared.option] : undefined;
51
+ if (server.inspectPort === undefined && typeof control === 'number')
52
+ server = { ...server, inspectPort: control };
47
53
  if (!database)
48
54
  return server;
49
55
  const backing = database;
@@ -69,7 +69,7 @@ export type LineShape = {
69
69
  * command-reply table reads them; moves `conn` past an intermediate reply. */
70
70
  check: (conn: LineConnection, line: string | null, codes: number[]) => string[];
71
71
  };
72
- /** The SHAPE of a line protocol (scripts/derive-pack.ts from an RFC's command-reply table): each reply a
72
+ /** The SHAPE of a line protocol (the derivation, from an RFC's command-reply table): each reply a
73
73
  * code the spec allows the command it answers, or one any command may answer. A line after an
74
74
  * intermediate reply (DATA's payload, a SASL response) is answered as that command's `then`. */
75
75
  export declare function lineShape(pkg: string): LineShape | undefined;
@@ -292,7 +292,7 @@ function unitResponseOwner(pkg, manifest) {
292
292
  };
293
293
  return { pathOf, checker };
294
294
  }
295
- /** The SHAPE of a line protocol (scripts/derive-pack.ts from an RFC's command-reply table): each reply a
295
+ /** The SHAPE of a line protocol (the derivation, from an RFC's command-reply table): each reply a
296
296
  * code the spec allows the command it answers, or one any command may answer. A line after an
297
297
  * intermediate reply (DATA's payload, a SASL response) is answered as that command's `then`. */
298
298
  export function lineShape(pkg) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-standard",
3
- "version": "1.0.159",
3
+ "version": "1.0.160",
4
4
  "description": "The Protocol 3 standard for Volter twin packs: the criteria a pack is graded by, the grader, the gate a pack repository and the twin catalog run on every change and submission, and the spec derivation the grade checks against. Pin a version: every place a pack is judged judges by that standard.",
5
5
  "keywords": [
6
6
  "twin",
@@ -77,8 +77,8 @@
77
77
  "yaml": "2.9.0"
78
78
  },
79
79
  "peerDependencies": {
80
- "@volter/world-core": "3.0.164",
81
- "@volter/world-runtime": "^3.0.188",
80
+ "@volter/world-core": "3.0.165",
81
+ "@volter/world-runtime": "^3.0.190",
82
82
  "playwright": "^1.63.0"
83
83
  },
84
84
  "peerDependenciesMeta": {
@@ -110,7 +110,9 @@
110
110
  "openai": "^7.25.0",
111
111
  "stripe": "^23.0.0",
112
112
  "@google/genai": "2.13.0",
113
- "@google/generative-ai": "0.24.1"
113
+ "@google/generative-ai": "0.24.1",
114
+ "nodemailer": "^10.0.6",
115
+ "twitter-api-v2": "^1.29.1"
114
116
  },
115
117
  "engines": {
116
118
  "node": ">=22.6"
@@ -2,13 +2,13 @@
2
2
  // check-sources — the evidence a derived pack cites, fetched (docs/contributing/architecture.md,
3
3
  // "Protocol 3", Correcting the spec and The semantics layer). Every URL a state transition's `source`,
4
4
  // 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
5
- // `quote` is looked for in the text of the page its `source` names. derive-pack reads the record offline
5
+ // `quote` is looked for in the text of the page its `source` names. the derivation reads the record offline
6
6
  // and refuses a dead source, one never checked, and a quote its page does not hold.
7
7
  //
8
8
  // Documentation pages, never a vendor's API: each is fetched at most once per run, sixteen at a time,
9
9
  // and a page already recorded as found is not fetched again (--recheck fetches everything).
10
10
  //
11
- // Usage: twin-standard check-sources <pack dir> [--recheck] (twin-world: bun scripts/check-sources.ts <vendor>)
11
+ // Usage: twin-standard check-sources <pack dir> [--recheck]
12
12
  import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
13
13
  import { dirname, join, resolve } from 'node:path';
14
14
  import { unitAt } from './unit.ts';
@@ -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": [
@@ -72,9 +72,7 @@ async function credentialFields(server: Served, door: NonNullable<PackDescriptor
72
72
  }
73
73
 
74
74
  /** The files conformance reads from a unit: its manifest, its spec's record, its vendor's life and its decision table
75
- * (a lane's journeys are its own `journeys/` or else its vendor's). A release publishes each (published()), and a
76
- * pack's standing counts it in the form only when every unit holds them (twin-world's scripts/pack-standing.ts, by
77
- * unitFilesMissing): the one list of both. */
75
+ * (a lane's journeys are its own `journeys/` or else its vendor's). A release publishes each (published()). */
78
76
  export const UNIT_FILES = ['src/manifest.ts', 'spec/SOURCE.md', 'journeys/customer-life.json', 'journeys/decisions.json'] as const;
79
77
 
80
78
  /** The published package must carry every conformance input its units hold, including lanes. */
@@ -89,8 +87,6 @@ export function unpublishedUnitFiles(unit: string): string[] {
89
87
  }).map((f) => `${f} is absent from package.json files (conformance reads it)`);
90
88
  }
91
89
 
92
- /** Each of UNIT_FILES a unit lacks where conformance reads it: the manifest of every unit, the life at its vendor's root
93
- * (lifeServed), the spec's record and the decision table of a unit with a spec (decided()). */
94
90
  const trackedJourneySources = new Map<string, string[]>();
95
91
  /** Table ownership follows one index snapshot per checkout/run. */
96
92
  function hasJourneySource(unit: string): boolean {
@@ -123,17 +119,6 @@ function hasJourneySource(unit: string): boolean {
123
119
  return source.some(path => path.startsWith(prefix));
124
120
  }
125
121
 
126
- export function unitFilesMissing(unit: string): string[] {
127
- const vendor = existsSync(join(unit, 'package.json')) ? unit : dirname(unit);
128
- const spec = hasOwnSurface(unit);
129
- const at: Record<(typeof UNIT_FILES)[number], string | undefined> = {
130
- 'src/manifest.ts': unit,
131
- 'spec/SOURCE.md': spec ? unit : undefined,
132
- 'journeys/customer-life.json': vendor,
133
- 'journeys/decisions.json': spec ? (hasJourneySource(unit) ? unit : vendor) : undefined,
134
- };
135
- 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)`);
136
- }
137
122
  /** A unit's fetch export: a pack's `create<Vendor>Fetch`, a lane's `create<Lane>LaneFetch`. */
138
123
  const fetchName = (dir: string): string => (existsSync(join(dir, 'package.json')) ? `create${pascal(basename(dir))}Fetch` : `create${pascal(basename(dir))}LaneFetch`);
139
124
  const manifestOf = async (unit: string): Promise<Manifest> => ((await import(join(unit, 'src', 'manifest.ts'))) as { manifest: Manifest }).manifest;
@@ -259,7 +244,7 @@ async function cited(pack: string): Promise<string[]> {
259
244
  const record = (readJson(join(unit, 'spec', 'sources.json')) ?? {}) as Record<string, SourceRecord>;
260
245
  for (const [url, quotes] of await citations(unit)) {
261
246
  const r = record[url];
262
- if (!r) { out.push(`${nameOf(pack, unit)}: ${url} is cited and not recorded (bun <twin-world>/scripts/check-sources.ts ${nameOf(pack, unit)})`); continue; }
247
+ if (!r) { out.push(`${nameOf(pack, unit)}: ${url} is cited and not recorded (twin-standard check-sources ${nameOf(pack, unit)})`); continue; }
263
248
  if (!sourceHeld(url, r)) out.push(`${nameOf(pack, unit)}: ${url} did not answer with verified evidence when checked`);
264
249
  for (const q of quotes) if (r.quotes?.[q] !== true) out.push(`${nameOf(pack, unit)}: "${q.slice(0, 80)}" is not on ${url}`);
265
250
  }
@@ -747,8 +732,8 @@ async function clientCases(pack: string, scratch: string, consumer?: ConsumerRes
747
732
  Object.assign(issued, (await credentialFields(server, door, host)).outputs);
748
733
  }
749
734
  const job = join(scratch, 'client-job.json');
750
- // a release carries its facts (generated/pack-facts.json, `twin-standard facts`); a source checkout does not, so its
751
- // facts are compiled here, as that command compiles them, for the client the case runs
735
+ // a pack carries its facts (generated/pack-facts.json, `twin-standard facts`), in source and release alike; one that
736
+ // has none yet has them compiled here, as that command compiles them, for the client the case runs
752
737
  let packFacts = join(pack, 'generated', 'pack-facts.json');
753
738
  if (!existsSync(packFacts)) {
754
739
  const { compilePackFacts, renderPackFacts } = await import('./pack-facts.ts');
@@ -2,8 +2,9 @@
2
2
  // create-pack — the files of a Protocol 3 pack that nobody should write (the board's `create-pack` card;
3
3
  // docs/contributing/architecture.md, "Creating a pack"), and the brief an author writes the rest from.
4
4
  //
5
- // bun scripts/create-pack.ts <dir> --init <vendor> write every fixed file of a new pack that does not exist yet
6
- // bun scripts/create-pack.ts <dir> --init <vendor> --lanes a,b
5
+ // twin-standard create <dir> --init <vendor> --package <@scope/name>
6
+ // write every fixed file of a new pack that does not exist yet
7
+ // twin-standard create <dir> --init <vendor> --package <@scope/name> --lanes a,b
7
8
  // the same for a pack of lanes, one per API of the vendor, each
8
9
  // derived from its own spec (<dir>/<lane>/spec): each lane's
9
10
  // manifest, fetch, index and semantics, and the pack's server
@@ -12,11 +13,11 @@
12
13
  // index}.ts, src/semantics/{states,shared,doors}.ts,
13
14
  // journeys/{demand,first-use}.json): the author fills the manifest's
14
15
  // vendor facts, the descriptor's hosts and the families
15
- // bun scripts/create-pack.ts <unit> --index write src/semantics/index.ts, the handler map, and src/fetch.ts from the
16
+ // twin-standard create <unit> --index write src/semantics/index.ts, the handler map, and src/fetch.ts from the
16
17
  // families' files (every exported function, by its name)
17
- // bun scripts/create-pack.ts <unit> --index --building the same during construction; unfinished operations stay gaps,
18
+ // twin-standard create <unit> --index --building the same during construction; unfinished operations stay gaps,
18
19
  // and implemented operations must match their decisions
19
- // bun scripts/create-pack.ts <unit> --brief [--out f] the author's brief: every operation the derived core does not
20
+ // twin-standard create <unit> --brief [--out f] the author's brief: every operation the derived core does not
20
21
  // serve and no handler answers yet, by family, with what the
21
22
  // vendored spec says of it (summary, description, parameters,
22
23
  // the answers it documents and their examples), so a handler
@@ -69,7 +70,7 @@ export function handlerIndex(dir: string): string {
69
70
  const ids = existsSync(surfacePath) ? ((parseExactJson(readFileSync(surfacePath, 'utf8')) as { operations?: Array<{ id: string }> }).operations ?? []).map((o) => o.id) : [];
70
71
  // an index written before the derive has no operations to map, and every served call would fall to the gap (404): refuse
71
72
  // it rather than write an empty map (2026-09-30: six packs committed so)
72
- if (!existsSync(surfacePath) && fams.length) throw new Error(`${dir}: no src/generated/surface.gen.json yet; derive the unit (scripts/derive-pack.ts) before --index`);
73
+ if (!existsSync(surfacePath) && fams.length) throw new Error(`${dir}: no src/generated/surface.gen.json yet; derive the unit (twin-standard derive) before --index`);
73
74
  const where = new Map(fams.flatMap((f) => f.handlers.map((h) => [h, f.family] as const)));
74
75
  const named = new Set([...new Set(ids)].map(handlerName));
75
76
  const stray = [...where.keys()].filter((h) => !named.has(h));
@@ -269,7 +270,7 @@ export async function brief(unit: string): Promise<string> {
269
270
  const s = spec.get(o.id);
270
271
  lines.push(`### ${o.id}${unmodeled.has(o.id) ? ' (unmodeled)' : ''}`, '', `\`${o.method.toUpperCase()} ${o.path}\` — ${o.class}${s?.summary ? `: ${oneLine(s.summary)}` : ''}`);
271
272
  // the citation a handler carries, ready to paste: by operationId where the spec names one, else by its JSON pointer,
272
- // quoting the spec's own words (derive-pack refuses a quote the spec does not hold)
273
+ // quoting the spec's own words (the derivation refuses a quote the spec does not hold)
273
274
  const words = oneLine(s?.summary ?? s?.description ?? '').split(/(?<=\.)\s/)[0]!.replace(/"/g, '\\"');
274
275
  const cite = s && (s as { operationId?: string }).operationId === o.id ? `spec:${o.id}` : `spec:/paths/${o.path.replace(/~/g, '~0').replace(/\//g, '~1')}/${o.method.toLowerCase()}`;
275
276
  if (words) lines.push('', `Cite: \`// source: ${cite} "${words}"\``);
@@ -331,7 +332,7 @@ export function packIndexFile(dir: string, vendor: string): string {
331
332
 
332
333
  /** A pack's `src/server.ts` (a fixed file), the kernel's serve seam around its fetch, naming only what its unit has so
333
334
  * it typechecks and a bundler follows every import: the plain seam (serveHttp, which takes the sockets a fetch carries
334
- * itself: "Other wires"), or, for a unit whose spec is a proto, the gRPC seam over the schema derive-pack generated
335
+ * itself: "Other wires"), or, for a unit whose spec is a proto, the gRPC seam over the schema the derivation generated
335
336
  * (src/generated/proto.gen.json, imported by its literal path). `--init` writes the plain one, `--index` the gRPC one once
336
337
  * the unit's proto is derived. */
337
338
  export function serverFile(vendor: string, grpc: boolean, wire = false, live = false): string {
@@ -436,7 +437,7 @@ export function initFiles(vendor: string): Record<string, string> {
436
437
  'src/semantics/states.ts': `// ${vendor}'s state machines and state rulings, each transition cited (architecture, "State").\nexport const states = {};\n`,
437
438
  '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`,
438
439
  '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`,
439
- '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`,
440
+ '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`,
440
441
  'src/server.ts': serverFile(vendor, false),
441
442
  'src/cli.ts': cliFile(vendor),
442
443
  '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`,
@@ -515,7 +516,7 @@ export async function fixedFiles(dir: string): Promise<Record<string, string>> {
515
516
  if (!vendor || !/^[a-z][a-z0-9-]*$/.test(vendor)) throw new Error('Pack manifest must declare its vendor identity independently of the npm package name');
516
517
  files['src/index.ts'] = packIndexFile(dir, vendor);
517
518
  if (!existsSync(join(dir, 'src', 'stream.ts'))) {
518
- // a unit whose spec is a proto (derive-pack generated its schema) is served over gRPC: its serve seam in that form
519
+ // a unit whose spec is a proto (the derivation generated its schema) is served over gRPC: its serve seam in that form
519
520
  const lanesOnly = !hasOwnSurface(dir) && readdirSync(dir).some((n) => existsSync(join(dir, n, 'src', 'manifest.ts')));
520
521
  const grpc = !lanesOnly && existsSync(join(dir, 'src', 'generated', 'proto.gen.json'));
521
522
  // a unit that takes broadcasts over RTMP (its manifest's `live`) has the live forms --index writes, so they reproduce
@@ -529,7 +530,7 @@ export async function fixedFiles(dir: string): Promise<Record<string, string>> {
529
530
  export async function createPack(args: string[]): Promise<void> {
530
531
  const [unit, ...rest] = args;
531
532
  if (!unit || (!rest.includes('--index') && !rest.includes('--brief') && !rest.includes('--init'))) {
532
- console.error('usage: bun scripts/create-pack.ts <dir> --init <vendor> | <unit> --index [--building] | --brief [--out <file>]');
533
+ console.error('usage: twin-standard create <dir> --init <vendor> --package <@scope/name> | <unit> --index [--building] | --brief [--out <file>]');
533
534
  process.exit(2);
534
535
  }
535
536
  if (rest.includes('--building') && (!rest.includes('--index') || rest.includes('--init') || rest.includes('--brief'))) {
@@ -598,7 +599,7 @@ export async function createPack(args: string[]): Promise<void> {
598
599
  console.log(`create-pack: wrote ${join(dir, 'src', 'index.ts')}`);
599
600
  // what the grade's typecheck compiles: a pack made before init wrote it gets it here
600
601
  if (!existsSync(join(dir, 'tsconfig.json'))) { writeFileSync(join(dir, 'tsconfig.json'), TSCONFIG); console.log(`create-pack: wrote ${join(dir, 'tsconfig.json')}`); }
601
- // a unit whose spec is a proto (derive-pack generated its schema) is served over gRPC: its serve seam in that form,
602
+ // a unit whose spec is a proto (the derivation generated its schema) is served over gRPC: its serve seam in that form,
602
603
  // 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)
603
604
  if (!lanesOnly && existsSync(join(dir, 'src', 'generated', 'proto.gen.json'))) {
604
605
  const wire = existsSync(join(dir, 'src', 'stream.ts'));
package/src/derive.ts CHANGED
@@ -5,7 +5,7 @@ import { parseExactJson, exactInteger } from '@volter/world-core/exact-json';
5
5
  // vendored spec (`<pack>/spec/openapi.json[.gz]`), builds the spec IR (./spec-ir.ts) and writes the pack's
6
6
  // `src/generated/`. Deterministic: a second run over the same spec writes the same bytes. Never hand-edit what it writes.
7
7
  //
8
- // Usage: twin-standard derive <pack dir> [--out <dir>] (twin-world: bun scripts/derive-pack.ts <vendor>)
8
+ // Usage: twin-standard derive <pack dir> [--out <dir>]
9
9
 
10
10
  import { parse as parseYaml } from 'yaml';
11
11
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
@@ -41,7 +41,7 @@ const PKG = unitAt(vendor).dir;
41
41
  const rfc = existsSync(join(PKG, 'spec')) ? readdirSync(join(PKG, 'spec')).find((f) => /^rfc\d+\.txt$/.test(f)) : undefined;
42
42
  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));
43
43
  if (!specPath) {
44
- 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`);
44
+ 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`);
45
45
  process.exit(SOURCE_REFUSAL);
46
46
  }
47
47
  const rpcService = basename(specPath) === 'proto';
@@ -308,7 +308,7 @@ if (existsSync(manifestPath)) {
308
308
  }
309
309
  // a resource's refresh scope ("The real-system adapters", What a pack declares) names the list that enumerates it or
310
310
  // its retrieve, or says why the vendor offers no read-back; whether every stored resource declares one is
311
- // pack-standing's report, not this build's
311
+ // not this build's to decide
312
312
  // (a resource the spec names is read by its own list or retrieve; one the manifest names apart from the spec's, an RPC
313
313
  // vendor's, by the list or read the scope names, with `items` where the answer holds them when the spec does not say)
314
314
  const specNamed = new Set(ir.resources.map((r) => r.name));
package/src/index.ts 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, type CriterionGrade, type GradeOptions, type StandardGrade } from './grade.ts';
7
- export { conformance, decisionTableProblems, type ConformanceResult, UNIT_FILES, unitFilesMissing } from './conformance.ts';
7
+ export { conformance, decisionTableProblems, type ConformanceResult, UNIT_FILES } from './conformance.ts';
8
8
  export { laneRootFailures, p3Gate, unitsOf } from './gate.ts';
9
9
  export { conformPublished, gatePublished, vendorOfPackage, type PublishedGate } from './published.ts';
10
10
  export { handlerName, protocol3, PLANNED, withCheckoutFiles } from './protocol-3.ts';
package/src/pack-facts.ts CHANGED
@@ -8,7 +8,7 @@ export type PackFacts = {
8
8
  serverBacking?: { command: string };
9
9
  maxRequestBodySize?: number;
10
10
  adoption?: { sdks?: string[]; pypi?: string[]; scopes?: string[]; envStems?: string[]; worldIds?: string[]; tools?: Array<{ package: string; usage: 'build' | 'deployment' }>; configFiles?: Array<{ file: string; usage: 'application' | 'build' | 'deployment'; when?: string }> };
11
- hosts?: Array<{ host?: string; suffix?: string; hostPattern?: string; pathPattern?: string; demandPathPattern?: string | false; key?: string; exclude?: true }>;
11
+ hosts?: Array<{ host?: string; suffix?: string; hostPattern?: string; pathPattern?: string; demandPathPattern?: string | false; key?: string; exclude?: true; basic?: string }>;
12
12
  hostsNone?: string;
13
13
  hostsClaimed?: { door: string; note: string };
14
14
  /** The subject types the twin projects (packRegistry `resources`) — invariant R2 at the resource
@@ -42,6 +42,8 @@ export type PackFacts = {
42
42
  managedDatabase?: { kind: 'postgres'; arg: string; user: string; database: string; clock: 'wall'; credentialField: string; note: string };
43
43
  /** Listeners the twin opens beside its main port (see TwinPack.sidePorts). */
44
44
  sidePorts?: Array<{ name: string; option: string; flag: string; path?: string; scheme?: string; note: string }>;
45
+ /** The vendor's own requests a World's generated seed makes (see TwinPack.seed). */
46
+ seed?: TwinPack['seed'];
45
47
  /** DERIVED, never declared: the pack's `create<Name>TwinServer` factory export — the
46
48
  * `({port,root,readOnly}) => {port,stop}` contract the colocated host mounts
47
49
  * (world-runtime/src/host.ts). Read off the module's own exports because the name is not
@@ -78,6 +80,7 @@ function validateHostRules(vendor: string, rules: NonNullable<PackFacts['hosts']
78
80
  try { new RegExp(rule.demandPathPattern); } catch (e) { throw new Error(`pack-facts: ${vendor} demandPathPattern does not compile: ${(e as Error).message}`); }
79
81
  }
80
82
  if (rule.exclude !== undefined && rule.exclude !== true) throw new Error(`pack-facts: ${vendor} host rule ${JSON.stringify(rule)} — exclude is \`true\` or absent, never a falsy flag`);
83
+ if (rule.basic !== undefined && (typeof rule.basic !== 'string' || !/^[^:\s]+$/.test(rule.basic) || rule.exclude)) throw new Error(`pack-facts: ${vendor} host rule ${JSON.stringify(rule)} — basic names a user (no colon, no space) on an included host`);
81
84
  const key = rule.key ?? vendor;
82
85
  // A foreign key is a WORLD identity too: `volter-world init` emits <KEY>_TWIN_URL only for the
83
86
  // ids in adoption.worldIds (covers.ts injectorVendorKeysFor), so a key not listed there would
@@ -221,6 +224,26 @@ export async function compilePackFacts(dirs: Array<{ vendor: string; dir: string
221
224
  }
222
225
  facts.sidePorts = pack.sidePorts;
223
226
  }
227
+ if (pack.seed !== undefined) {
228
+ // 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
229
+ // is a `/_twin/` stand-in
230
+ const seed = pack.seed as Record<string, unknown>;
231
+ const door = (value: unknown, what: string, standIn = false): void => {
232
+ let url: URL;
233
+ try { url = new URL(String(value)); } catch { throw new Error(`pack-facts: ${vendor} seed ${what} "${String(value)}" is not a URL`); }
234
+ if (url.protocol !== 'https:') throw new Error(`pack-facts: ${vendor} seed ${what} is the vendor's own https request`);
235
+ if (!standIn && url.pathname.startsWith('/_twin/')) throw new Error(`pack-facts: ${vendor} seed ${what} is the vendor's own request, never a /_twin/ door`);
236
+ };
237
+ if (!seed || typeof seed !== 'object' || Array.isArray(seed) || Object.keys(seed).some((k) => k !== 'signUp' && k !== 'domain')) throw new Error(`pack-facts: ${vendor} seed is { signUp?, domain? }`);
238
+ if (seed.signUp !== undefined) door(seed.signUp, 'signUp');
239
+ if (seed.domain !== undefined) {
240
+ const domain = seed.domain as Record<string, unknown>;
241
+ if (!domain || typeof domain !== 'object' || Array.isArray(domain) || Object.keys(domain).sort().join() !== 'add,record,settles,verify') throw new Error(`pack-facts: ${vendor} seed.domain is { add, record, verify, settles }`);
242
+ door(domain.add, 'domain.add'); door(domain.verify, 'domain.verify'); door(domain.record, 'domain.record', true);
243
+ if (typeof domain.settles !== 'string' || !/^\d+[smhd]$/.test(domain.settles)) throw new Error(`pack-facts: ${vendor} seed.domain.settles is a World-clock time (10m)`);
244
+ }
245
+ facts.seed = pack.seed;
246
+ }
224
247
  // The serve factory is DERIVED from the module's exports (see PackFacts.serveExport);
225
248
  // a pack exporting SEVERAL factories must declare which one `cli.ts serve` boots — the
226
249
  // exports alone cannot reveal that judgment (linear defaults to its DERIVED server).
@@ -240,7 +263,7 @@ export async function compilePackFacts(dirs: Array<{ vendor: string; dir: string
240
263
  if (Object.keys(facts).length > 0) packs[vendor] = facts;
241
264
  }
242
265
  return {
243
- '//': 'GENERATED by scripts/pack-facts.ts — current pack descriptors and explicit world-runtime server backings; no prior-artifact entries are retained.',
266
+ '//': 'GENERATED by twin-standard facts from the pack descriptor; no prior-artifact entries are retained.',
244
267
  packs: sortObject(packs),
245
268
  undeclared,
246
269
  };
package/src/protocol-3.ts CHANGED
@@ -171,7 +171,7 @@ function noReport(unit: GradeUnit): string {
171
171
  /** An operation's family: the first segment of its path after a version (`/v1/organizations/{id}` is `organizations`), a
172
172
  * dotted RPC method's first part (`chat.postMessage` is `chat`), a line command's name (architecture, "Pack layout"). */
173
173
  function familyOf(path: string): string {
174
- // the interim rule ("What an author writes"), until derive-pack writes the spec's own grouping on each operation
174
+ // the interim rule ("What an author writes"), until the derivation writes the spec's own grouping on each operation
175
175
  const segs = path.split('/').filter((x) => x && !/^v?\d+(\.\d+)?$|^\d{4}-\d{2}-\d{2}$/.test(x) && !x.startsWith('{'));
176
176
  if (!segs.length) return 'operations'; // named in a header: every path is `/`
177
177
  const first = segs[0]!;
@@ -262,7 +262,7 @@ const criteria: Criterion[] = [
262
262
  },
263
263
  {
264
264
  id: 'derived-reproducible', section: 'form',
265
- asks: 'derive-pack regenerates src/generated/ byte for byte',
265
+ asks: 'twin-standard derive regenerates src/generated/ byte for byte',
266
266
  check(unit) {
267
267
  const gen = join(unit.dir, 'src', 'generated');
268
268
  if (!existsSync(gen)) return fail('src/generated/ is missing');
@@ -279,9 +279,9 @@ const criteria: Criterion[] = [
279
279
  // the pack's own path and the scratch directory are this checkout's, not the pack's: the verdict names neither, so
280
280
  // a standing written from one checkout reads the same from any other
281
281
  if (run.status === null || run.signal !== null || run.error) return { pass: false, cacheable: false,
282
- reason: `derive-pack interrupted: status=${run.status} signal=${run.signal} error=${run.error?.message ?? ''}` };
283
- if (run.status !== 0) 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 };
284
- 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`);
282
+ reason: `derive interrupted: status=${run.status} signal=${run.signal} error=${run.error?.message ?? ''}` };
283
+ if (run.status !== 0) 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 };
284
+ 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`);
285
285
  },
286
286
  },
287
287
  {
@@ -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
 
8
8
  export type CommandArgument = { name: string; type: string; optional?: boolean; multiple?: boolean; token?: string; arguments?: CommandArgument[] };
9
9
  /** A command: `id` as a client names it (`SET`, `CLIENT GETNAME` for a container's subcommand); `arity` as Redis gives
@@ -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
@@ -161,7 +161,7 @@ export function parseProto(path: string, text: string): ProtoFile {
161
161
  return file;
162
162
  }
163
163
 
164
- /** The vendored tree (path → text) as data, so a spec patch corrects it as it corrects a JSON spec (derive-pack). */
164
+ /** The vendored tree (path → text) as data, so a spec patch corrects it as it corrects a JSON spec (twin-standard derive). */
165
165
  export type ProtoSpec = { format: 'proto'; files: ProtoFile[] };
166
166
  export function readProtoFiles(files: Record<string, string>): ProtoSpec {
167
167
  return { format: 'proto', files: Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([path, text]) => parseProto(path, text)) };
@@ -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
 
5
5
  export type SpecPatch = { op: string; path: string; from?: string; value?: unknown };
6
6
 
@@ -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.ts';
9
8
  import { createHash } from 'node:crypto';
10
9
  import { existsSync, readFileSync } from 'node:fs';
@@ -24,8 +24,8 @@
24
24
  // A walk that fails, and a file in scope (the pack's src/ on disk, its sharing lanes' too) that declares code yet
25
25
  // measures no line, stop the measurement: neither is a file with nothing to reach.
26
26
  //
27
- // Usage: twin-standard coverage <vendor> [--write | --out <file>] [--prune] (from the pack repository's root; twin-world's
28
- // bun scripts/life-coverage.ts runs the same) (--prune removes the stale records) (--write keeps journeys/coverage.json)
27
+ // Usage: twin-standard coverage <vendor> [--write | --out <file>] [--prune] (from the pack repository's root)
28
+ // (--prune removes the stale records) (--write keeps journeys/coverage.json)
29
29
  import { spawnSync } from 'node:child_process';
30
30
  import ts from 'typescript';
31
31
  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
 
8
8
  let packs = process.cwd();
@@ -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
 
@@ -35,8 +35,7 @@
35
35
  // read for. `--sweep` prints, without changing done, every actor field (creator, user, *_by, ...) no `equals` pins and every
36
36
  // list no expect closes: advice for fixing a ruling as a class (its hits include lists a pinned text already fixes).
37
37
  //
38
- // Usage: twin-standard examples <vendor> [--sweep] (from the pack repository's root; twin-world's
39
- // bun scripts/vendor-examples.ts <vendor> runs the same)
38
+ // Usage: twin-standard examples <vendor> [--sweep] (from the pack repository's root)
40
39
  import { parseExactJson, exactInteger, isExactIntegerValue } from '@volter/world-core/exact-json';
41
40
  import { hasOwnSurface } from '../lanes.ts';
42
41
  import { archiveSource } from '../archive-source.ts';
@@ -95,7 +94,7 @@ function answerKeys(output: unknown, published: unknown, sent: unknown, placehol
95
94
  return mapped(output);
96
95
  }
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<T extends object>(pkg: string, doc: T): T {
@@ -376,7 +375,7 @@ function fromSpec(pkg: string, lane: string | undefined, model: SmithyModel | un
376
375
  }
377
376
  return out;
378
377
  }
379
- // a spec vendored as published or gzipped, as derive-pack reads it
378
+ // a spec vendored as published or gzipped, as the derivation reads it
380
379
  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));
381
380
  // a Protocol Buffers service publishes no examples in its .proto files: its examples are its documentation's alone
382
381
  if (!spec && existsSync(join(pkg, 'spec', 'proto'))) return [];
@@ -390,7 +389,7 @@ function fromSpec(pkg: string, lane: string | undefined, model: SmithyModel | un
390
389
  const text = spec ? (spec.endsWith('.gz') ? gunzipSync(readFileSync(spec)) : readFileSync(spec)).toString('utf8') : '';
391
390
  type Op = { operationId?: string; responses?: Record<string, Record<string, unknown>>; 'x-oaiMeta'?: { examples?: unknown } };
392
391
  type Doc = { paths: Record<string, Record<string, Op>>; components?: { examples?: Record<string, { value?: unknown }>; schemas?: Record<string, SpecSchema> }; definitions?: Record<string, SpecSchema> };
393
- // a Google API Discovery document publishes no examples; it is read as the OpenAPI document derive-pack reads it as,
392
+ // a Google API Discovery document publishes no examples; it is read as the OpenAPI document the derivation reads it as,
394
393
  // its patches applied to the Discovery document first (spec-ir-discovery.ts)
395
394
  const discovery = spec !== undefined && /discovery\.json(\.gz)?$/.test(spec);
396
395
  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)]) as Doc[];
package/src/verdict.ts CHANGED
@@ -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
 
7
7
  /** Committed attribution names people or author roles, never execution identities. */
@@ -14,7 +14,7 @@ import { createRequire } from 'node:module';
14
14
  import { gzipSync } from 'node:zlib';
15
15
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
16
16
  import { join } from 'node:path';
17
- import { databaseSession, type DatabaseSession, getActivePackAssets, getActiveWorldStore, LocalPackAssets, MemoryBlobStore, MemoryWorldStore, setActiveBlobStore, setActivePackAssets, setActiveWorldStore, setDeliveryObserver, setInProcessTwins, settleEventDeliveries, worldDoorMatcher, worldNow, type InProcessTwin, type TwinStream, type TwinStreamConnection } from '@volter/world-core/runtime';
17
+ import { databaseSession, type DatabaseSession, getActivePackAssets, getActiveWorldStore, LocalPackAssets, MemoryBlobStore, MemoryWorldStore, setActiveBlobStore, setActivePackAssets, setActiveWorldStore, setDeliveryObserver, setInProcessMailServers, setInProcessTwins, settleEventDeliveries, worldDoorMatcher, worldNow, type InProcessTwin, type TwinStream, type TwinStreamConnection } from '@volter/world-core/runtime';
18
18
  import { createHostTable, type HostFacts } from '@volter/world-core/host-routing';
19
19
  import packFactsDocument from '@volter/world-core/generated/pack-facts.json' with { type: 'json' };
20
20
  import { type Captured, type GitStep, type Journey, type JourneyStep, type LineStep, type SocketStep, type SqlStep, type RespStep, type MysqlStep, type MongoStep, isMongo, isMysql, isResp, at, captureAt, echoFailures, expandFills, expectFailures, fill, fillJson, formBody, isGit, isLine, isSql, isSocket, isWait, jwtAuthorization, oauth1Authorization, presignedPath, sigv4Headers, waitMs } from './journey-kit.ts';
@@ -237,6 +237,17 @@ export async function walk(journey: Journey, root: string, collect: Failure[], o
237
237
  if (!companion || !keys.length) { collect.push({ step: '(setup)', beat: 'ADAPTER', detail: vendor === journey.vendor ? `the life's own vendor ${vendor} is no companion of it` : !companion ? `no create<Name>Fetch adapter for the companion ${vendor}` : `the companion ${vendor} declares no host rules (pack facts) a call could reach it by` }); return {}; }
238
238
  companions.push({ vendor, keys, fetch: companion(root, { application }), databaseDoor: companion.managedDatabaseDoor });
239
239
  }
240
+ // a companion that receives mail (an SMTP side port: gmail's, gmail.com's MX) is the mail server ctx.mail reaches for
241
+ // the domains its host rules claim, on its byte-stream door in process over this walk's World, as a World reaches its
242
+ // listener: the life declares the provider of every address it mails
243
+ const mailServers: Array<{ vendor: string; receives: (domain: string) => boolean; stream: TwinStream }> = [];
244
+ for (const c of companions) {
245
+ const sides = (walkFacts[c.vendor.split('/')[0]!] as { sidePorts?: Array<{ scheme?: string }> } | undefined)?.sidePorts ?? [];
246
+ if (!sides.some((side) => side.scheme === 'smtp')) continue;
247
+ const stream = await vendorStream(packsDir(), c.vendor, dependenciesDir());
248
+ if (!stream) { collect.push({ step: '(setup)', beat: 'ADAPTER', detail: `the companion ${c.vendor} receives mail on an smtp side port and exports no create<Name>TwinStream` }); return {}; }
249
+ mailServers.push({ vendor: c.vendor, receives: (domain) => c.keys.some((key) => walkHosts[key]!(domain, '/')), stream: stream(root, { application }) });
250
+ }
240
251
  const eventFields = new Map<string, Set<string>>();
241
252
  for (const vendor of [journey.vendor, ...companions.map((companion) => companion.vendor)]) {
242
253
  const directory = directoryFor(vendor);
@@ -735,6 +746,7 @@ export async function walk(journey: Journey, root: string, collect: Failure[], o
735
746
  ...companions.flatMap((c) => c.keys.map((key) => [key, c.fetch] as const)),
736
747
  ...ownKeys.map((key) => [key, twin] as const),
737
748
  ]));
749
+ const previousMailServers = setInProcessMailServers(mailServers);
738
750
  try {
739
751
  for (const step of journey.steps) {
740
752
  await settleEventDeliveries(root);
@@ -938,6 +950,7 @@ export async function walk(journey: Journey, root: string, collect: Failure[], o
938
950
  } finally {
939
951
  setDeliveryObserver(previousObserver);
940
952
  setInProcessTwins(previousTwins);
953
+ setInProcessMailServers(previousMailServers);
941
954
  try {
942
955
  if (sqlSession) await sqlSession.then((session) => session.end(), () => {});
943
956
  } finally {