@volter/twin-standard 1.0.149 → 1.0.150

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 (83) hide show
  1. package/README.md +12 -3
  2. package/client-sdks/bun.lock +0 -32
  3. package/client-sdks/package.json +0 -2
  4. package/dist/client-sdks/bun.lock +0 -32
  5. package/dist/client-sdks/package.json +0 -2
  6. package/dist/src/assessment.d.ts +5 -4
  7. package/dist/src/assessment.js +2 -1
  8. package/dist/src/cli.js +21 -6
  9. package/dist/src/clients/harness.d.ts +3 -1
  10. package/dist/src/clients/harness.js +4 -2
  11. package/dist/src/clients/jira.d.ts +2 -0
  12. package/dist/src/clients/jira.js +71 -0
  13. package/dist/src/clients/polar.d.ts +2 -0
  14. package/dist/src/clients/polar.js +73 -0
  15. package/dist/src/clients/resend.js +38 -0
  16. package/dist/src/clients/run.js +1 -1
  17. package/dist/src/clients/sentry.js +1 -26
  18. package/dist/src/clients/smtp.d.ts +2 -0
  19. package/dist/src/clients/smtp.js +54 -0
  20. package/dist/src/clients/stripe.js +1 -1
  21. package/dist/src/clients/volteridentity.js +4 -3
  22. package/dist/src/clients/x.d.ts +2 -0
  23. package/dist/src/clients/x.js +64 -0
  24. package/dist/src/conformance.d.ts +4 -1
  25. package/dist/src/conformance.js +256 -6
  26. package/dist/src/consumer.js +5 -1
  27. package/dist/src/create-pack.d.ts +5 -0
  28. package/dist/src/create-pack.js +31 -3
  29. package/dist/src/protocol-3.js +30 -2
  30. package/dist/src/spec-ir.d.ts +2 -0
  31. package/dist/src/spec-ir.js +43 -0
  32. package/dist/src/tools/judge-brief.d.ts +1 -0
  33. package/dist/src/tools/judge-brief.js +67 -0
  34. package/dist/src/tools/life-coverage-walk.d.ts +2 -0
  35. package/dist/src/tools/life-coverage-walk.js +220 -0
  36. package/dist/src/tools/life-coverage.d.ts +2 -0
  37. package/dist/src/tools/life-coverage.js +271 -0
  38. package/dist/src/tools/packs-root.d.ts +9 -0
  39. package/dist/src/tools/packs-root.js +17 -0
  40. package/dist/src/tools/run-tool.d.ts +1 -0
  41. package/dist/src/tools/run-tool.js +18 -0
  42. package/dist/src/tools/score-pack.d.ts +2 -0
  43. package/dist/src/tools/score-pack.js +264 -0
  44. package/dist/src/tools/vendor-examples.d.ts +2 -0
  45. package/dist/src/tools/vendor-examples.js +1493 -0
  46. package/dist/src/verdict.js +1 -1
  47. package/dist/src/walk/behavior-journey.d.ts +6 -0
  48. package/dist/src/walk/behavior-journey.js +8 -6
  49. package/dist/src/walk/journey-kit.d.ts +2 -0
  50. package/dist/src/walk/journey-kit.js +6 -2
  51. package/dist/src/walk/rendered-scalar.d.ts +3 -0
  52. package/dist/src/walk/rendered-scalar.js +23 -0
  53. package/dist/src/walk/sse-example.js +45 -0
  54. package/package.json +2 -2
  55. package/src/assessment.ts +2 -1
  56. package/src/cli.ts +15 -2
  57. package/src/clients/harness.ts +4 -2
  58. package/src/clients/jira.ts +73 -0
  59. package/src/clients/polar.ts +73 -0
  60. package/src/clients/resend.ts +32 -0
  61. package/src/clients/run.ts +2 -2
  62. package/src/clients/sentry.ts +1 -25
  63. package/src/clients/smtp.ts +49 -0
  64. package/src/clients/stripe.ts +1 -1
  65. package/src/clients/volteridentity.ts +4 -3
  66. package/src/clients/x.ts +66 -0
  67. package/src/conformance.ts +192 -8
  68. package/src/consumer.ts +5 -1
  69. package/src/create-pack.ts +27 -3
  70. package/src/protocol-3.ts +24 -2
  71. package/src/spec-ir.ts +31 -0
  72. package/src/tools/judge-brief.ts +63 -0
  73. package/src/tools/life-coverage-walk.ts +173 -0
  74. package/src/tools/life-coverage.ts +237 -0
  75. package/src/tools/packs-root.ts +21 -0
  76. package/src/tools/run-tool.ts +10 -0
  77. package/src/tools/score-pack.ts +244 -0
  78. package/src/tools/vendor-examples.ts +1250 -0
  79. package/src/verdict.ts +1 -1
  80. package/src/walk/behavior-journey.ts +6 -2
  81. package/src/walk/journey-kit.ts +7 -2
  82. package/src/walk/rendered-scalar.ts +17 -0
  83. package/src/walk/sse-example.ts +37 -0
@@ -7,7 +7,7 @@
7
7
  export function attributionName(name) {
8
8
  if (name === undefined)
9
9
  return undefined;
10
- if (/\bcx-|\bt_[0-9a-f]{8}|wt\/|\/root(?:\/|$|[: )])|\b(?:pane|session)[ -:]|[0-9a-f]{8}-[0-9a-f-]{27}|\b[0-9a-f]{16,64}\b/i.test(name))
10
+ if (/\bcx-|\bt_[0-9a-f]{8}|wt\/|\/root(?:\/|$|[: )])|\b(?:pane|session)[ :-]|[0-9a-f]{8}-[0-9a-f-]{27}|\b[0-9a-f]{16,64}\b/i.test(name))
11
11
  throw new Error('attribution must use an author name, not an execution identifier');
12
12
  return name;
13
13
  }
@@ -18,6 +18,12 @@ export type Failure = {
18
18
  beat: string;
19
19
  detail: string;
20
20
  };
21
+ /** What a stored row keeps for the twin that no schema of the vendor's spec names, by path, in anything the World shows a
22
+ * client: the pack's `_`-prefixed bookkeeping (GitHub's `_links` is the vendor's), and, in what no answer's SHAPE
23
+ * reads (an event's delivery, a socket frame), the kernel's own `updatedAt`, which a raw row filtered on `_` alone
24
+ * carries (Slack's message events once did). The kernel's `deleted` is not read there: vendors send their own
25
+ * (Stripe's deleted customer's `deleted: true`). */
26
+ export declare function leaked(v: unknown, vendorFields: Set<string>, at?: string, unshaped?: boolean): string[];
21
27
  /** What a caller that scores a walk observes around each step: the step, its resolved path and body,
22
28
  * and (after) the answer and the failures the step produced. */
23
29
  export type StepHooks = {
@@ -151,7 +151,7 @@ const claims = (keys, url) => {
151
151
  * reads (an event's delivery, a socket frame), the kernel's own `updatedAt`, which a raw row filtered on `_` alone
152
152
  * carries (Slack's message events once did). The kernel's `deleted` is not read there: vendors send their own
153
153
  * (Stripe's deleted customer's `deleted: true`). */
154
- function leaked(v, vendorFields, at = '', unshaped = false) {
154
+ export function leaked(v, vendorFields, at = '', unshaped = false) {
155
155
  if (Array.isArray(v))
156
156
  return v.flatMap((x, i) => leaked(x, vendorFields, `${at}[${i}]`, unshaped)).slice(0, 5);
157
157
  if (!v || typeof v !== 'object')
@@ -1172,13 +1172,15 @@ export async function walk(journey, root, collect, opts) {
1172
1172
  let res;
1173
1173
  if (deferred) {
1174
1174
  pending.delete(step.await);
1175
- try {
1176
- res = await deferred.answer;
1177
- }
1178
- catch (error) {
1179
- collect.push({ step: step.name, beat: 'PENDING', detail: String(error) });
1175
+ const got = await deferred.answer.then((a) => ({ a }), (error) => ({ error }));
1176
+ // a body the vendor broke off, as the collect expects (`breaks`): its words are the answer
1177
+ if ('error' in got) {
1178
+ if (step.breaks === undefined || !String(got.error).includes(step.breaks))
1179
+ collect.push({ step: step.name, beat: 'PENDING', detail: String(got.error) });
1180
1180
  continue;
1181
1181
  }
1182
+ // over a listener, which ends a broken stream as a short body, the ordinary checks hold the part that arrived
1183
+ res = got.a;
1182
1184
  }
1183
1185
  else
1184
1186
  res = await send({ ...step, body, headers, ...(formed ? { formed } : {}) }, path);
@@ -10,6 +10,8 @@ export type JourneyStep = {
10
10
  defer?: string;
11
11
  /** Collect a previously deferred request once, with all ordinary response checks. */
12
12
  await?: string;
13
+ /** A collect whose answer's body breaks off with these words (a stream the vendor ends in an error), not arriving whole. */
14
+ breaks?: string;
13
15
  body?: unknown;
14
16
  /** A body of raw bytes (a gzip'd package, an image, an audio file), base64 in the journey and sent decoded: a
15
17
  * string body is sent as UTF-8, which no binary format survives. A step carries `body` or `bodyBase64`, never both. */
@@ -112,8 +112,9 @@ export function expectFailures(expect, body, captured, headers = {}, wireText) {
112
112
  if (e.contains !== undefined) {
113
113
  const want = fill(e.contains, captured);
114
114
  const text = typeof v === 'string' ? v : JSON.stringify(v ?? '');
115
+ // what it holds instead, its first characters, so a failure says what the twin answered
115
116
  if (!text.includes(want))
116
- out.push(`${e.path || 'the answer'} does not contain ${JSON.stringify(want)}`);
117
+ out.push(`${e.path || 'the answer'} does not contain ${JSON.stringify(want)} (it begins ${JSON.stringify(text.replace(/\s+/g, ' ').slice(0, 160))})`);
117
118
  }
118
119
  // `notContains`: the value does not hold the text (a list that omits what the caller may not see)
119
120
  if (e.notContains !== undefined) {
@@ -337,7 +338,10 @@ export function fill(template, captured, graphqlDocument = false) {
337
338
  }
338
339
  // a doubled brace is the vendor's own template syntax ({{sample.output_text}} in an OpenAI grader), not a capture; a
339
340
  // capture's name starts with a letter, so a pattern's count (`[A-Za-z0-9]{40}` in an expectation) is no capture
340
- return encoded.replace(/\{\{[^{}]*\}\}|\{([A-Za-z_][A-Za-z0-9_.]*)\}/g, (m, key, offset) => {
341
+ // `{literal:word}` is `{word}` as the vendor's page prints it (a Redis hash tag, `{queue}`), never a capture
342
+ return encoded.replace(/\{literal:([^{}]*)\}|\{\{[^{}]*\}\}|\{([A-Za-z_][A-Za-z0-9_.]*)\}/g, (m, literal, key, offset) => {
343
+ if (literal !== undefined)
344
+ return `{${literal}}`;
341
345
  if (selections.has(offset))
342
346
  return m;
343
347
  if (key === undefined)
@@ -0,0 +1,3 @@
1
+ export declare function renderedScalar(value: unknown, types: unknown[], enumerated: boolean): symbol | undefined;
2
+ export declare function isRenderedScalar(value: unknown): boolean;
3
+ export declare function matchesRenderedScalar(marker: unknown, value: unknown): boolean;
@@ -0,0 +1,23 @@
1
+ /** Unfilled scalar type words in schema-rendered examples. Real values and enum words remain literal. */
2
+ const BOOLEAN = Symbol('rendered boolean');
3
+ const INTEGER = Symbol('rendered integer');
4
+ const NUMBER = Symbol('rendered number');
5
+ export function renderedScalar(value, types, enumerated) {
6
+ if (enumerated || typeof value !== 'string')
7
+ return undefined;
8
+ if (value === 'boolean' && types.includes('boolean'))
9
+ return BOOLEAN;
10
+ if (value === 'integer' && types.includes('integer'))
11
+ return INTEGER;
12
+ if (value === 'number' && types.includes('number'))
13
+ return NUMBER;
14
+ return undefined;
15
+ }
16
+ export function isRenderedScalar(value) { return value === BOOLEAN || value === INTEGER || value === NUMBER; }
17
+ export function matchesRenderedScalar(marker, value) {
18
+ if (marker === BOOLEAN)
19
+ return typeof value === 'boolean';
20
+ if (marker === INTEGER)
21
+ return typeof value === 'bigint' || (typeof value === 'number' && Number.isInteger(value));
22
+ return marker === NUMBER && typeof value === 'number' && Number.isFinite(value);
23
+ }
@@ -1,6 +1,8 @@
1
1
  import { parseExactJson } from '@volter/world-core/exact-json';
2
2
  /** Match a published SDK-decoded SSE sample to a real HTTP frame; preserve non-SSE answers and mismatches. */
3
3
  export function sseExampleAnswer(example, answer, matches) {
4
+ if (typeof example === 'string' && typeof answer === 'string')
5
+ return streamSample(example, answer);
4
6
  if (typeof answer !== 'string' || !example || typeof example !== 'object')
5
7
  return answer;
6
8
  const wrapped = 'data' in example;
@@ -30,3 +32,46 @@ export function sseExampleAnswer(example, answer, matches) {
30
32
  const candidates = relevant.map((frame) => wrapped ? frame : frame.data);
31
33
  return candidates.find(matches) ?? candidates[0] ?? answer;
32
34
  }
35
+ /** A stream's frames: each block's `event:` and joined `data:` lines, or a block that is JSON alone (a page printing the
36
+ * chunks without their framing); `[DONE]`, an elision (`...`, `....`) and anything else not JSON are no frame. */
37
+ function framesOf(text) {
38
+ const frames = [];
39
+ for (const block of text.replace(/\r\n/g, '\n').split(/\n\s*\n/)) {
40
+ const lines = block.split('\n').map((l) => l.trim()).filter(Boolean);
41
+ const framed = lines.some((l) => l.startsWith('data:'));
42
+ const data = framed ? lines.filter((l) => l.startsWith('data:')).map((l) => l.slice(5).trim()).join('\n') : lines.join('\n');
43
+ if (!data || data === '[DONE]' || /^\.{3,}$/.test(data))
44
+ continue;
45
+ const event = lines.find((l) => l.startsWith('event:'))?.slice(6).trim();
46
+ try {
47
+ frames.push({ data: parseExactJson(data), ...(event ? { event } : {}) });
48
+ }
49
+ catch { /* not a JSON frame */ }
50
+ }
51
+ return frames;
52
+ }
53
+ const kindOf = (v) => (v === null ? 'null' : Array.isArray(v) ? 'array' : typeof v);
54
+ /** Whether an answer's frame holds a published frame's keys with the same kinds of value (a null published value admits
55
+ * any), its type or object the same. */
56
+ function holds(published, got) {
57
+ if (!published || typeof published !== 'object' || Array.isArray(published))
58
+ return kindOf(published) === kindOf(got) || published === null;
59
+ if (!got || typeof got !== 'object' || Array.isArray(got))
60
+ return false;
61
+ const p = published, g = got;
62
+ for (const key of ['type', 'object'])
63
+ if (typeof p[key] === 'string' && p[key] !== g[key])
64
+ return false;
65
+ return Object.entries(p).every(([k, v]) => k in g && (v === null || kindOf(v) === kindOf(g[k]) || (kindOf(v) === 'object' && holds(v, g[k]))));
66
+ }
67
+ /** A published stream printed as text (a page's sample of a stream, its middle elided): each frame it shows has a frame
68
+ * of the answer holding it, the answer then standing for the sample; else the answer, unchanged, which the literal
69
+ * comparison reports. */
70
+ function streamSample(example, answer) {
71
+ const published = framesOf(example);
72
+ if (published.length < 2)
73
+ return answer;
74
+ const frames = framesOf(answer);
75
+ const held = published.every((p) => frames.some((f) => (!p.event || p.event === f.event) && holds(p.data, f.data)));
76
+ return held ? example : answer;
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-standard",
3
- "version": "1.0.149",
3
+ "version": "1.0.150",
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",
@@ -75,7 +75,7 @@
75
75
  "yaml": "2.9.0"
76
76
  },
77
77
  "peerDependencies": {
78
- "@volter/world-core": "3.0.156",
78
+ "@volter/world-core": "3.0.157",
79
79
  "@volter/world-runtime": "*",
80
80
  "playwright": "^1.63.0"
81
81
  },
package/src/assessment.ts CHANGED
@@ -93,5 +93,6 @@ export async function assessPack(packDir: string, options: AssessmentOptions = {
93
93
  try { consumer = options.consumer ? await runConsumerWorkflow(packDir, options.consumer) : { measured: false, passed: false, failures: ['Installed customer workflow was not prepared'] }; }
94
94
  catch (error) { consumer = { measured: false, passed: false, failures: [(error as Error).message] }; }
95
95
  const ready = gates.length > 0 && gates.every((gate) => !gate.failures.length) && !quick.failures.length && replayEqual && conform !== null && conform.length > 0 && conform.every((result) => !result.failures.length) && consumer.measured && consumer.passed && (!options.browser || !httpOnly || browser.measured === true && (browser.failures as unknown[]).length === 0 && (browser.replay as { equal: boolean }).equal);
96
- return { schemaVersion: 1, vendor, package: manifest.name, version: manifest.version, ready, gates: gates.map((gate) => ({ ...gate, unit: gate.unit === packDir ? vendor : `${vendor}/${gate.unit.slice(packDir.length + 1)}` })), quick, browser, conformance: conform, consumer };
96
+ // the artifact assessed, by the integrity its prepared consumer verified the installed candidate against (consumer.ts)
97
+ return { schemaVersion: 1, vendor, package: manifest.name, version: manifest.version, ...((consumer as { integrity?: string }).integrity ? { integrity: (consumer as { integrity?: string }).integrity } : {}), ready, gates: gates.map((gate) => ({ ...gate, unit: gate.unit === packDir ? vendor : `${vendor}/${gate.unit.slice(packDir.length + 1)}` })), quick, browser, conformance: conform, consumer };
97
98
  }
package/src/cli.ts CHANGED
@@ -13,6 +13,12 @@
13
13
  // the pack served and read as an application and the
14
14
  // catalog meet it (conformance.ts): a checkout, or a
15
15
  // published version as the catalog admits it; or exit 1
16
+ // twin-standard walk <vendor> [--write] [--report <file>] the journey test, from the pack repository's root: the
17
+ // life walked on a fresh World (twice, the same), its
18
+ // coverage and the published examples (tools/score-pack.ts)
19
+ // twin-standard examples <vendor> [--sweep] the vendor's published examples replayed (tools/vendor-examples.ts)
20
+ // twin-standard coverage <vendor> [--write | --out <file>] the code and state logic the walks reach (tools/life-coverage.ts)
21
+ // twin-standard judge-brief <vendor> --authors <names> what an independent judge reads and writes (tools/judge-brief.ts)
16
22
  // twin-standard --version the package's version and each standard's
17
23
  import { existsSync, readFileSync } from 'node:fs';
18
24
  import { relative, resolve } from 'node:path';
@@ -24,7 +30,7 @@ import { gatePublished } from './published.ts';
24
30
 
25
31
  const [command, ...args] = process.argv.slice(2);
26
32
  const usage = (): never => {
27
- console.error('usage: twin-standard gate <repo> [units…] | gate-published <name>@<version>… [--registry <url>] | grade <unit>… [--static] [--form] | derive <unit> [--out <dir>] | read-page <url> [--raw] | check-sources <unit> [--recheck] | conform <pack dir> | <name>@<version> [--registry <url>] | create <dir> --init <vendor> --package <@scope/name> | create <unit> --index [--building] | facts <pack dir> [--out <file>] | prepare-consumer <pack dir> --app <new dir> --cli <volter executable> --integrity <sha512> --out <json> [--candidate <tgz>] | walk-consumer <pack dir> --prepared-consumer <json> [--out <file>] | assess <pack dir> --prepared-consumer <json> [--browser] [--out <file>] | --version');
33
+ console.error('usage: twin-standard gate <repo> [units…] | gate-published <name>@<version>… [--registry <url>] | grade <unit>… [--static] [--form] | derive <unit> [--out <dir>] | read-page <url> [--raw] | check-sources <unit> [--recheck] | conform <pack dir> | <name>@<version> [--registry <url>] | create <dir> --init <vendor> --package <@scope/name> | create <unit> --index [--building] | facts <pack dir> [--out <file>] | prepare-consumer <pack dir> --app <new dir> --cli <volter executable> --integrity <sha512> --out <json> [--candidate <tgz>] | walk-consumer <pack dir> --prepared-consumer <json> [--out <file>] | assess <pack dir> --prepared-consumer <json> [--browser] [--out <file>] | walk <vendor> [--write] [--report <file>] | examples <vendor> [--sweep] | coverage <vendor> [--write | --out <file>] | judge-brief <vendor> --authors <names> | --version');
28
34
  process.exit(2);
29
35
  };
30
36
 
@@ -133,6 +139,13 @@ if (command === '--version') {
133
139
  mkdirSync(dirname(out), { recursive: true });
134
140
  writeFileSync(out, renderPackFacts(facts));
135
141
  console.log(out);
142
+ } else if (command === 'walk' || command === 'examples' || command === 'coverage' || command === 'judge-brief') {
143
+ // the contributor's journey tools, run from the pack repository's root (tools/packs-root.ts), each a script over
144
+ // process.argv whose first argument is the vendor
145
+ if (!args[0] || args[0].startsWith('-')) usage();
146
+ const tool = { walk: 'score-pack', examples: 'vendor-examples', coverage: 'life-coverage', 'judge-brief': 'judge-brief' }[command];
147
+ process.argv = [process.argv[0]!, process.argv[1]!, ...args];
148
+ await import((await import('./tools/packs-root.ts')).toolPath(tool));
136
149
  } else if (command === 'derive') {
137
150
  if (!args[0]) usage();
138
151
  // the derivation is a script over process.argv: it reads the unit from its first argument
@@ -157,7 +170,7 @@ if (command === '--version') {
157
170
  const published = target.endsWith('.tgz') || (!existsSync(target) && /^@?[^@]+@[^@]+$/.test(target));
158
171
  const results = published
159
172
  ? await (await import('./published.ts')).conformPublished(target, at >= 0 ? { registry: args[at + 1]! } : {})
160
- : await (await import('./conformance.ts')).conformance(target);
173
+ : await (await import('./conformance.ts')).conformance(target, { onCheck: (id) => console.error(` … ${id} (${new Date().toISOString().slice(11, 19)})`) });
161
174
  for (const r of results) {
162
175
  console.log(`${r.failures.length ? '✗' : '✓'} ${r.id.padEnd(15)} ${r.asks}${r.note ? ` (${r.note})` : ''}`);
163
176
  for (const f of r.failures) console.log(` ${f}`);
@@ -106,13 +106,15 @@ export function servedHttpFetch(port: number): typeof fetch {
106
106
  }
107
107
 
108
108
  /** The context for a pack reached at `port` of this machine (the World's proxy in front of it). */
109
- export function clientContext(port: number, host: string, env: Record<string, string>, scenarioPath: string): ClientContext {
109
+ /** `raw`: a raw protocol's served port (SMTP's listener), which a connection reaches directly, as a World passes a raw TCP
110
+ * connection through untouched; the proxy speaks HTTP only. */
111
+ export function clientContext(port: number, host: string, env: Record<string, string>, scenarioPath: string, raw?: number): ClientContext {
110
112
  const agent = new (class extends HttpsAgent {
111
113
  createConnection(): Socket { return connect(port, '127.0.0.1'); }
112
114
  })({ keepAlive: false });
113
115
  return {
114
116
  host, env, fetch: servedHttpFetch(port), agent,
115
- connect: () => connect(port, '127.0.0.1'),
117
+ connect: () => connect(raw ?? port, '127.0.0.1'),
116
118
  scenario: (doc) => writeFileSync(scenarioPath, JSON.stringify(doc)),
117
119
  };
118
120
  }
@@ -0,0 +1,73 @@
1
+ // jira.js 5.4.0, unmodified (Twin's on-call agent's client: cookbook/on-call-agent/agent.mjs), as that agent constructs
2
+ // it: a Version3Client on the site's URL with Basic authentication by an account's email and API token, its axios
3
+ // requests through the World's routed HTTPS agent. The site, its admin and the token are made at the pack's doors, as a
4
+ // person makes them at Atlassian's sign-up and account console.
5
+ import type { ClientCase, ClientContext } from './harness.ts';
6
+
7
+ const README = 'https://www.npmjs.com/package/jira.js/v/5.4.0';
8
+ const CREATE = 'https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-post';
9
+ const ADF = 'https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/';
10
+
11
+ /** A site named `slug`, its admin, the admin's API token and a project OPS led by them; the client on the site's URL. */
12
+ async function site(c: ClientContext, slug: string, apiToken?: string) {
13
+ const door = async (path: string, body: unknown) => {
14
+ const answer = await c.fetch(`https://${c.host}${path}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
15
+ if (answer.status !== 201) throw new Error(`${path} answered ${answer.status}`);
16
+ return (await answer.json()) as Record<string, string>;
17
+ };
18
+ const email = `admin@${slug}.example`;
19
+ const made = await door('/_twin/sites', { name: slug, admin: { name: 'Admin', email, password: 'sdk-case-2026' } });
20
+ const token = apiToken ?? (await door('/_twin/api-token', { site: slug, email, password: 'sdk-case-2026' })).apiToken!;
21
+ const { Version3Client } = await import('jira.js');
22
+ const jira = new Version3Client({ host: `https://${slug}.atlassian.net`, authentication: { basic: { email, apiToken: token } }, baseRequestConfig: { httpsAgent: c.agent } });
23
+ return { jira, admin: made.admin! };
24
+ }
25
+
26
+ export const cases: ClientCase[] = [
27
+ {
28
+ id: 'create-issue-string-description',
29
+ asks: "an issue filed as the on-call agent files it, its description a plain string the client sends as an ADF document, answers its id, key and self, and reads back with that text",
30
+ source: `${CREATE} "Creates an issue or, where the option to create subtasks is enabled in Jira, a subtask."`,
31
+ async run(c) {
32
+ const { jira, admin } = await site(c, 'sdk-file');
33
+ await jira.projects.createProject({ key: 'OPS', name: 'Operations', projectTypeKey: 'software', leadAccountId: admin });
34
+ const filed = await jira.issues.createIssue({ fields: { project: { key: 'OPS' }, issuetype: { name: 'Task' }, summary: 'acme/web#1: checkout fails', description: 'SEVERITY: high — checkout fails' } });
35
+ const failures: string[] = [];
36
+ if (!/^OPS-\d+$/.test(String(filed.key)) || !filed.id || !String(filed.self).includes(`/rest/api/3/issue/${filed.id}`)) failures.push(`createIssue answered ${JSON.stringify(filed)}`);
37
+ const read = await jira.issues.getIssue({ issueIdOrKey: String(filed.key), fields: ['summary', 'description'] });
38
+ const text = JSON.stringify(read.fields.description ?? null);
39
+ if (read.fields.summary !== 'acme/web#1: checkout fails') failures.push(`the issue reads back summary ${JSON.stringify(read.fields.summary)}`);
40
+ if (!text.includes('"type":"doc"') || !text.includes('SEVERITY: high — checkout fails')) failures.push(`the description reads back ${text.slice(0, 160)}, not the ADF document of the text sent`);
41
+ return failures;
42
+ },
43
+ },
44
+ {
45
+ id: 'adf-document-shape',
46
+ asks: 'a description read back is an ADF document: type doc, version 1, its paragraph holding the text node',
47
+ source: `${ADF} "Atlassian Document Format (ADF) represents rich text stored in Atlassian products."`,
48
+ async run(c) {
49
+ const { jira, admin } = await site(c, 'sdk-adf');
50
+ await jira.projects.createProject({ key: 'OPS', name: 'Operations', projectTypeKey: 'software', leadAccountId: admin });
51
+ const filed = await jira.issues.createIssue({ fields: { project: { key: 'OPS' }, issuetype: { name: 'Task' }, summary: 'shape', description: 'one line' } });
52
+ const doc = (await jira.issues.getIssue({ issueIdOrKey: String(filed.key), fields: ['description'] })).fields.description as { type?: string; version?: number; content?: Array<{ type?: string; content?: Array<{ type?: string; text?: string }> }> } | undefined;
53
+ return doc?.type === 'doc' && doc.version === 1 && doc.content?.[0]?.type === 'paragraph' && doc.content[0].content?.[0]?.type === 'text' && doc.content[0].content[0].text === 'one line'
54
+ ? [] : [`the description is ${JSON.stringify(doc).slice(0, 200)}`];
55
+ },
56
+ },
57
+ {
58
+ id: 'wrong-token-http-exception',
59
+ asks: 'a request with an API token the account never made is refused, and the client throws its HttpException carrying the status',
60
+ source: `${README} "\`HttpException\`: Server responded with an error (includes parsed error details)"`,
61
+ async run(c) {
62
+ const { HttpException } = await import('jira.js');
63
+ const { jira } = await site(c, 'sdk-refused', 'ATATT-not-a-token-this-account-made');
64
+ try {
65
+ await jira.projects.searchProjects({ maxResults: 50 });
66
+ return ['the made-up token was accepted'];
67
+ } catch (error) {
68
+ if (!(error instanceof HttpException)) return [`the refusal is not an HttpException: ${String(error).slice(0, 160)}`];
69
+ return error.status === 401 ? [] : [`the refusal's status is ${error.status}, not 401`];
70
+ }
71
+ },
72
+ },
73
+ ];
@@ -0,0 +1,73 @@
1
+ // Polar's TypeScript SDK, unmodified (@polar-sh/sdk 0.49, Twin's billing app: apps/billing/src/polar.ts), with the
2
+ // Organization Access Token the World's credential door issues. The SDK validates every answer against its own models,
3
+ // so a case that reads one back has held the answer's shape too. It sends through the global fetch, so the World's
4
+ // routed fetch is set before it is made.
5
+ import type { ClientCase, ClientContext } from './harness.ts';
6
+
7
+ const INGEST = 'https://polar.sh/docs/api-reference/events/ingest';
8
+ const STATE = 'https://polar.sh/docs/api-reference/customers/state-external';
9
+ const PRODUCTS = 'https://polar.sh/docs/api-reference/products/create';
10
+
11
+ async function client(c: ClientContext) {
12
+ globalThis.fetch = c.fetch;
13
+ const { Polar } = await import('@polar-sh/sdk');
14
+ return new Polar({ accessToken: c.env.POLAR_ACCESS_TOKEN, server: 'production' });
15
+ }
16
+
17
+ export const cases: ClientCase[] = [
18
+ {
19
+ id: 'catalog-bootstrap',
20
+ asks: "the billing app's boot: a meter made by its filter and aggregation, and a monthly product priced fixed and per metered unit with a trial, each read back by name in the SDK's own models",
21
+ source: `${PRODUCTS} "plus any number of metered prices"`,
22
+ async run(c) {
23
+ const polar = await client(c);
24
+ const meter = await polar.meters.create({ name: 'case_world_hours', filter: { conjunction: 'and', clauses: [{ property: 'name', operator: 'eq', value: 'world.hour' }] }, aggregation: { func: 'sum', property: 'units' } });
25
+ const product = await polar.products.create({
26
+ name: 'Case Team', recurringInterval: 'month', description: 'A case plan',
27
+ prices: [{ amountType: 'fixed', priceAmount: 4900, priceCurrency: 'usd' }, { amountType: 'metered_unit', unitAmount: '2', meterId: meter.id }],
28
+ trialInterval: 'day', trialIntervalCount: 14,
29
+ });
30
+ const failures: string[] = [];
31
+ const meters = await polar.meters.list({ limit: 100 });
32
+ if (!meters.result.items.some((m) => m.id === meter.id && m.name === 'case_world_hours')) failures.push('the made meter is not listed by its name');
33
+ const products = await polar.products.list({ limit: 100 });
34
+ const listed = products.result.items.find((p) => p.id === product.id);
35
+ if (!listed || listed.name !== 'Case Team' || listed.isArchived) failures.push(`the made product lists as ${JSON.stringify(listed && { name: listed.name, isArchived: listed.isArchived })}`);
36
+ if (product.prices.length !== 2) failures.push(`the product holds ${product.prices.length} prices, not its fixed and metered two`);
37
+ if (product.trialInterval !== 'day' || product.trialIntervalCount !== 14) failures.push(`the product's trial is ${String(product.trialIntervalCount)} ${String(product.trialInterval)}`);
38
+ return failures;
39
+ },
40
+ },
41
+ {
42
+ id: 'unknown-customer-state-not-found',
43
+ asks: "an organization with no customer reads as the SDK's ResourceNotFound (404), which the billing app takes as Free",
44
+ source: `${STATE} "Customer not found."`,
45
+ async run(c) {
46
+ const polar = await client(c);
47
+ const { ResourceNotFound } = await import('@polar-sh/sdk/models/errors/resourcenotfound.js');
48
+ try {
49
+ await polar.customers.getStateExternal({ externalId: 'org_never_a_customer' });
50
+ return ['an unknown external id read as a customer'];
51
+ } catch (error) {
52
+ return error instanceof ResourceNotFound ? [] : [`the refusal is not ResourceNotFound: ${String(error).slice(0, 160)}`];
53
+ }
54
+ },
55
+ },
56
+ {
57
+ id: 'ingest-deduplicates-by-external-id',
58
+ asks: 'an event sent again with the same external_id (a tick retried after a timeout) is skipped as a duplicate, not counted twice',
59
+ source: `${INGEST} "Number of duplicate events skipped."`,
60
+ async run(c) {
61
+ const polar = await client(c);
62
+ const customer = await polar.customers.create({ email: 'ops@case-ingest.example', externalId: 'org_case_ingest' });
63
+ const event = { name: 'world.hour', externalCustomerId: 'org_case_ingest', externalId: 'tick-2026-01-14T10', metadata: { units: 1 } };
64
+ const first = await polar.events.ingest({ events: [event] });
65
+ const again = await polar.events.ingest({ events: [event] });
66
+ const failures: string[] = [];
67
+ if (first.inserted !== 1 || first.duplicates !== 0) failures.push(`the first send answered ${JSON.stringify(first)}`);
68
+ if (again.inserted !== 0 || again.duplicates !== 1) failures.push(`the retried send answered ${JSON.stringify(again)}, not one duplicate skipped`);
69
+ if (!customer.id) failures.push('the customer was made with no id');
70
+ return failures;
71
+ },
72
+ },
73
+ ];
@@ -56,4 +56,36 @@ export const cases: ClientCase[] = [
56
56
  return answer.data === null && answer.error?.statusCode === 422 && answer.error?.name === 'missing_required_field' ? [] : [`missing sender returned ${JSON.stringify(answer)}`];
57
57
  },
58
58
  },
59
+ {
60
+ id: 'unverified-domain-validation-error',
61
+ asks: 'a send from a domain the team never verified comes back as the SDK error validation_error (403), with no data',
62
+ source: `${ERRORS} "To send emails to other recipients, please verify a domain at resend.com/domains, and change the \`from\` address to an email using this domain."`,
63
+ async run(c) {
64
+ const resend = client(c);
65
+ const sent = await resend.emails.send({ from: 'Someone <someone@never-verified.example>', to: ['client@example.org'], subject: 'Not from a verified domain', text: 'Refused.' });
66
+ const failures: string[] = [];
67
+ if (sent.data !== null) failures.push(`the send answered data ${JSON.stringify(sent.data)}`);
68
+ const error = sent.error as { name?: string; statusCode?: number | null } | null;
69
+ if (error?.name !== 'validation_error') failures.push(`the error is ${JSON.stringify(error)}, not validation_error`);
70
+ else if (error.statusCode !== 403) failures.push(`the validation_error's status is ${String(error.statusCode)}, not 403`);
71
+ return failures;
72
+ },
73
+ },
74
+ {
75
+ id: 'scheduled-send-waits',
76
+ asks: "a send scheduled for later (the SDK's scheduledAt, sent as scheduled_at) waits: it reads back scheduled, at its time",
77
+ source: `${SEND} "Schedule email to be sent later."`,
78
+ async run(c) {
79
+ const resend = client(c);
80
+ const at = '2030-01-01T08:00:00.000Z';
81
+ const sent = await resend.emails.send({ from: 'Acme <onboarding@resend.dev>', to: ['owner@world.test'], subject: 'Later', text: 'In good time.', scheduledAt: at });
82
+ if (sent.error || !sent.data?.id) return [`the send answered ${JSON.stringify(sent).slice(0, 200)}`];
83
+ const read = await resend.emails.get(sent.data.id);
84
+ const email = read.data as { last_event?: string; scheduled_at?: string | null } | null;
85
+ const failures: string[] = [];
86
+ if (email?.last_event !== 'scheduled') failures.push(`the scheduled email's last_event is ${String(email?.last_event)}`);
87
+ if (email?.scheduled_at === undefined || email.scheduled_at === null || Date.parse(email.scheduled_at) !== Date.parse(at)) failures.push(`it reads back scheduled_at ${String(email?.scheduled_at)}`);
88
+ return failures;
89
+ },
90
+ },
59
91
  ];
@@ -7,7 +7,7 @@ import { extname } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
8
  import { clientContext, worldProxy, type ClientCase } from './harness.ts';
9
9
 
10
- const job = JSON.parse(readFileSync(process.argv[2]!, 'utf8')) as { vendor: string; port: number; host: string; env: Record<string, string>; scenarioPath: string; packFacts: string };
10
+ const job = JSON.parse(readFileSync(process.argv[2]!, 'utf8')) as { vendor: string; port: number; host: string; env: Record<string, string>; scenarioPath: string; packFacts: string; raw?: boolean };
11
11
  const { cases } = (await import(`./${job.vendor}${extname(fileURLToPath(import.meta.url))}`)) as { cases: ClientCase[] };
12
12
  if (!Array.isArray(cases) || cases.length === 0) throw new Error(`${job.vendor} client module declares no cases; there is no SDK execution evidence`);
13
13
  // every connection a case makes goes through the World's proxy, as an application's does in a World
@@ -19,7 +19,7 @@ require('@volter/world-core/pack-facts').extendPackFacts([job.packFacts]);
19
19
  const facts = JSON.parse(readFileSync(job.packFacts, 'utf8')).packs[job.vendor];
20
20
  const keys: string[] = [...new Set<string>((facts.hosts ?? []).map((rule: { key?: string }) => rule.key ?? job.vendor))];
21
21
  require('@volter/world-core/inject').install(Object.fromEntries(keys.map((key) => [key, `http://127.0.0.1:${proxy}`])));
22
- const context = clientContext(proxy, job.host, job.env, job.scenarioPath);
22
+ const context = clientContext(proxy, job.host, job.env, job.scenarioPath, job.raw ? job.port : undefined);
23
23
  for (const c of cases) {
24
24
  const failures = await Promise.race([
25
25
  c.run(context).catch((e: Error) => [`the case threw: ${e.message}`]),
@@ -22,7 +22,6 @@ async function sdkOf(name: string): Promise<any> {
22
22
  const pins = [
23
23
  ['rallly', '@sentry/node', '10.38.0'],
24
24
  ['twenty', 'sentry-node-twenty', '10.73.0'],
25
- ['postiz', 'sentry-node-postiz', '10.56.0'],
26
25
  ['cal-api', 'sentry-node-cal', '9.46.0'],
27
26
  ['cal-web', 'sentry-node-cal-web', '10.33.0'],
28
27
  ] as const;
@@ -67,7 +66,7 @@ export const cases: ClientCase[] = pins.map(([application, name, version]) => ({
67
66
  },
68
67
  }));
69
68
 
70
- for (const [name, version] of [['@sentry/browser', '10.38.0'], ['sentry-browser-twenty', '10.59.0'], ['sentry-browser-postiz', '10.56.0']] as const) cases.push({
69
+ for (const [name, version] of [['@sentry/browser', '10.38.0'], ['sentry-browser-twenty', '10.59.0']] as const) cases.push({
71
70
  id: 'browser-' + version + '-dsn-query-auth-and-session-envelope',
72
71
  asks: 'the browser fetch transport uses DSN query authentication and flushes event and session envelopes',
73
72
  source: `https://unpkg.com/@sentry/core@${version}/build/esm/api.js "sentry_key: publicKey"`,
@@ -133,26 +132,3 @@ cases.push({
133
132
  });
134
133
 
135
134
 
136
- cases.push({
137
- id: 'postiz-feedback-attribution',
138
- asks: 'captureFeedback preserves the widget message, explicit name/email, associated event and scoped user',
139
- source: 'https://unpkg.com/@sentry/core@10.56.0/build/esm/feedback.js "associated_event_id: associatedEventId"',
140
- async run(c) {
141
- const sdk = await sdkOf('sentry-browser-postiz');
142
- const client = new sdk.BrowserClient({ dsn: c.env.SENTRY_DSN, integrations: [], stackParser: sdk.defaultStackParser,
143
- transport: (options: any) => sdk.createTransport(options, async (request: { body: string | Uint8Array }) => {
144
- const answer = await c.fetch(options.url, { method: 'POST', body: request.body as BodyInit });
145
- return { statusCode: answer.status, headers: {} };
146
- }) });
147
- let id = '';
148
- sdk.withScope((scope: any) => {
149
- scope.setClient(client); scope.setUser({ id: 'feedback-author' });
150
- id = sdk.captureFeedback({ message: 'The scheduling button is hard to find', name: 'Priya', email: 'priya@harbourline.test', associatedEventId: '00000000000000000000000000000002' }, {}, scope);
151
- });
152
- const drained = await client.flush(10_000);
153
- const event = await read(c, id, await token(c));
154
- await client.close(10_000);
155
- const feedback = event.contexts?.feedback;
156
- return drained && event.type === 'feedback' && event.user?.id === 'feedback-author' && feedback?.name === 'Priya' && feedback?.contact_email === 'priya@harbourline.test' && feedback?.associated_event_id === '00000000000000000000000000000002' ? [] : ['feedback attribution or associated event was lost'];
157
- },
158
- });
@@ -0,0 +1,49 @@
1
+ // Nodemailer 10, unmodified, as Dub, Rallly, Cal.com, Twenty and LibreChat send their mail: its SMTP transport, plain
2
+ // on the relay's port, given the World's TCP connection through its getSocket hook (SMTP is a raw protocol: the case
3
+ // names a stand-in relay host the connection never resolves). The relay's policy at boot asks no authentication.
4
+ import type { ClientCase, ClientContext } from './harness.ts';
5
+
6
+ const RFC5321 = 'https://www.rfc-editor.org/rfc/rfc5321';
7
+
8
+ async function transport(c: ClientContext) {
9
+ const nodemailer = (await import('nodemailer')).default;
10
+ return nodemailer.createTransport({
11
+ host: c.host, port: 25, secure: false, ignoreTLS: true,
12
+ getSocket: (_options: unknown, callback: (error: Error | null, socket?: { connection: unknown }) => void) => callback(null, { connection: c.connect() }),
13
+ } as never);
14
+ }
15
+
16
+ export const cases: ClientCase[] = [
17
+ {
18
+ id: 'verify-greets',
19
+ asks: "nodemailer's verify opens the session, greets with EHLO and quits: the relay answers it as an SMTP server",
20
+ source: `${RFC5321} "These commands are used to identify the SMTP client to the SMTP server."`,
21
+ async run(c) {
22
+ const t = await transport(c);
23
+ try {
24
+ return (await t.verify()) === true ? [] : ['verify resolved without true'];
25
+ } catch (error) {
26
+ return [`verify failed: ${String(error).slice(0, 200)}`];
27
+ } finally { t.close(); }
28
+ },
29
+ },
30
+ {
31
+ id: 'transaction-to-two-recipients',
32
+ asks: 'a message with text and HTML to two recipients runs MAIL, a RCPT for each, then DATA: both accepted, none rejected, the data answered 250',
33
+ source: `${RFC5321} "Once started, a mail transaction consists of a transaction beginning command, one or more RCPT commands, and a DATA command, in that order."`,
34
+ async run(c) {
35
+ const t = await transport(c);
36
+ try {
37
+ const info = await t.sendMail({ from: 'Polls <polls@case.example>', to: ['an@case.example', 'bo@case.example'], subject: 'Pick a date', text: 'Please pick a date.', html: '<p>Please pick a date.</p>' }) as { accepted: string[]; rejected: string[]; response: string; messageId: string };
38
+ const failures: string[] = [];
39
+ if (JSON.stringify([...info.accepted].sort()) !== JSON.stringify(['an@case.example', 'bo@case.example'])) failures.push(`accepted ${JSON.stringify(info.accepted)}`);
40
+ if (info.rejected.length) failures.push(`rejected ${JSON.stringify(info.rejected)}`);
41
+ if (!info.response.startsWith('250')) failures.push(`the data was answered ${info.response}`);
42
+ if (!info.messageId) failures.push('no message id');
43
+ return failures;
44
+ } catch (error) {
45
+ return [`the send failed: ${String(error).slice(0, 200)}`];
46
+ } finally { t.close(); }
47
+ },
48
+ },
49
+ ];
@@ -1,4 +1,4 @@
1
- // Stripe's own client (stripe-node), driving the stripe pack as its applications do (Cal.com, Dub, Postiz, Rallly and
1
+ // Stripe's own client (stripe-node), driving the stripe pack as its applications do (Cal.com, Dub, Rallly and
2
2
  // Twenty call it): an endpoint registered through the API and the event Stripe sends it verified by constructEvent, as an
3
3
  // application's webhook handler verifies it; a customer list read page by page by the client's auto-pagination; a retry
4
4
  // sent with its idempotency key; the error a missing object raises; and the customer portal a billing page opens.
@@ -1,9 +1,10 @@
1
1
  // @volter/identity 0.4.1, as Volter Harness uses it; discovery and token verification are also the APIs Open Autonomy
2
- // uses in 0.1.0. These cases are owned by conformance and are not run during pack authoring.
2
+ // uses in 0.1.0. These cases are owned by conformance and are not run during pack authoring. They import nothing of the
3
+ // kernel: the runner is Node's own type stripping, which the kernel's parameter properties do not pass.
3
4
  import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
4
5
  import { tmpdir } from 'node:os';
5
6
  import { join } from 'node:path';
6
- import { digest } from '@volter/world-core';
7
+ import { createHash } from 'node:crypto';
7
8
  import { resolveIdentity, verifyIdentityToken, tokenFor, readSharedSignIn, SHARED_CLIENTS } from '@volter/identity';
8
9
  import type { ClientCase, ClientContext } from './harness.ts';
9
10
 
@@ -36,7 +37,7 @@ async function setup(c: ClientContext, name: string, shared = false): Promise<{
36
37
  await send(c, `/admin/clients/${registered.client_id}/resources`, { resource: 'https://teams.sdk.example' }, operator);
37
38
  }
38
39
  const verifier = 'official-sdk-case-verifier-with-enough-entropy-for-s256';
39
- const query = new URLSearchParams({ client_id: registered.client_id, redirect_uri: callback, response_type: 'code', scope: 'openid profile email offline_access', code_challenge: digest('sha256', verifier, 'base64url'), code_challenge_method: 'S256' });
40
+ const query = new URLSearchParams({ client_id: registered.client_id, redirect_uri: callback, response_type: 'code', scope: 'openid profile email offline_access', code_challenge: createHash('sha256').update(verifier).digest('base64url'), code_challenge_method: 'S256' });
40
41
  const authorized = await send(c, `/api/auth/oauth2/authorize?${query}`, undefined, { cookie });
41
42
  const code = new URL(authorized.headers.get('location')!).searchParams.get('code')!;
42
43
  const form = new URLSearchParams({ client_id: registered.client_id, redirect_uri: callback, grant_type: 'authorization_code', code, code_verifier: verifier, ...(registered.client_secret ? { client_secret: registered.client_secret } : {}) });