pomerado 0.1.0 → 0.1.2

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 (41) hide show
  1. package/README.md +4 -2
  2. package/dist/typescript/authoring/core/SKILL.md +12 -0
  3. package/dist/typescript/authoring/examples/dates-and-dropdowns.js +5 -2
  4. package/dist/typescript/authoring/examples/dates-and-dropdowns.ts +5 -2
  5. package/dist/typescript/authoring/examples/dates-and-files.d.ts +4 -4
  6. package/dist/typescript/authoring/examples/dates-and-files.js +5 -5
  7. package/dist/typescript/authoring/examples/dates-and-files.ts +5 -5
  8. package/dist/typescript/authoring/examples/dialog-picker.d.ts +2 -2
  9. package/dist/typescript/authoring/examples/dialog-picker.js +3 -3
  10. package/dist/typescript/authoring/examples/dialog-picker.ts +3 -3
  11. package/dist/typescript/authoring/examples/native-dialog.d.ts +2 -2
  12. package/dist/typescript/authoring/examples/native-dialog.js +3 -3
  13. package/dist/typescript/authoring/examples/native-dialog.ts +3 -3
  14. package/dist/typescript/authoring/examples/navigation.d.ts +4 -4
  15. package/dist/typescript/authoring/examples/navigation.js +8 -5
  16. package/dist/typescript/authoring/examples/navigation.ts +8 -5
  17. package/dist/typescript/authoring/examples/parser.d.ts +2 -2
  18. package/dist/typescript/authoring/examples/parser.js +1 -1
  19. package/dist/typescript/authoring/examples/parser.ts +1 -1
  20. package/dist/typescript/authoring/examples/write-session.d.ts +13 -13
  21. package/dist/typescript/authoring/examples/write-session.js +9 -9
  22. package/dist/typescript/authoring/examples/write-session.ts +9 -9
  23. package/dist/typescript/src/guardian/upstream-policy.d.ts +2 -1
  24. package/dist/typescript/src/guardian/upstream-policy.js +10 -3
  25. package/dist/typescript/src/guardian/upstream-policy.md +9 -0
  26. package/dist/typescript/src/mint/contracts.d.ts +9 -2
  27. package/dist/typescript/src/mint/contracts.js +8 -0
  28. package/dist/typescript/src/mint/harness.js +5 -1
  29. package/dist/typescript/src/mint/incident-contracts.d.ts +6 -6
  30. package/dist/typescript/src/mint/publication-block.js +2 -1
  31. package/dist/typescript/src/mint/registry-feedback.js +4 -0
  32. package/dist/typescript/src/mint/sign-in-failure.d.ts +2 -2
  33. package/dist/typescript/src/registry/issues.d.ts +3 -1
  34. package/dist/typescript/src/registry/site-naming.d.ts +7 -0
  35. package/dist/typescript/src/registry/site-naming.js +6 -0
  36. package/dist/typescript/src/runtime/failure-detail.d.ts +10 -11
  37. package/dist/typescript/src/runtime/failure-detail.js +41 -45
  38. package/dist/typescript/tests/support/credential-masking-corpus.js +2 -2
  39. package/package.json +9 -2
  40. package/third-party/codex/LICENSE +201 -0
  41. package/third-party/codex/NOTICE +6 -0
package/README.md CHANGED
@@ -246,9 +246,9 @@ corepack pnpm test:browser
246
246
 
247
247
  This repository owns the portable tests for its shared core and local runtime, with synthetic fixtures and the existing Vitest and Playwright runners. Browser tests exercise native Playwright, minting through MCP, generated integration MCPs, authentication and autofill using local fixture sites and scripted model responses. They need no Cloud account or model API key. Tests for hosted services stay in the application repository.
248
248
 
249
- Open shared core and local adapter pull requests here. Shared changes land here first.
249
+ Outside pull requests are not accepted until a Contributor License Agreement is in place. Issues are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for how changes land and [SECURITY.md](SECURITY.md) for reporting vulnerabilities privately.
250
250
 
251
- Public tests use synthetic sites and data. Keep customer-specific incidents, private credentials and internal issue references out of public contributions.
251
+ Public tests use synthetic sites and data. Keep customer-specific incidents, private credentials and internal issue references out of public contributions. CI enforces this with a gitleaks secret scan and a public content scan. Run `node tools/check-public-content.ts` before you push. Link a public issue by its full URL.
252
252
 
253
253
  - Build and test the package before publishing an explicit versioned release. The release workflow validates the packed artifact before npm publication.
254
254
  - Adopt a tested release in Cloud through an exact dependency pin and locked integrity. Update the controller and sandbox images together.
@@ -259,3 +259,5 @@ The clone and build quickstart works independently of npm releases. Contributors
259
259
  ---
260
260
 
261
261
  Copyright (c) 2026 Pomerado. Licensed under GNU Affero General Public License version 3 only (`AGPL-3.0-only`). See [LICENSE](LICENSE).
262
+
263
+ Third-party code keeps its own license. The Guardian policy in `typescript/src/guardian/upstream-policy.md` is adapted from [OpenAI Codex](https://github.com/openai/codex) under the Apache License 2.0. Its license and notice are in [third-party/codex/](third-party/codex/) and ship with the npm package.
@@ -140,6 +140,18 @@ request and the flow, never from one caller's account or example.
140
140
  schema, inside `Schema.optional(...)` for an optional one; a `Schema.Date` keeps it only on
141
141
  `Schema.optional(Schema.Date)` or `Schema.propertySignature(Schema.Date)`. Callers see each
142
142
  beside its name.
143
+ - Shape inputs and outputs like Pomerado's own API, so every tool reads alike: field names in
144
+ snake_case; dates as `YYYY-MM-DD` and timestamps as ISO 8601 with an offset; money as an
145
+ integer in minor units with an ISO 4217 `currency` beside it, such as `total_minor` 12999 and
146
+ `currency` `"USD"`; enum values in lowercase snake_case (`"premium_economy"`); booleans named
147
+ as statements (`refundable`, not `is_refundable_flag`); lists named in the plural; and the
148
+ unit in the field name or its description (`duration_minutes`). Convert between these and the
149
+ site's own formats in code.
150
+ - Give every input field one `examples` annotation value, which callers, the docs and the Try it
151
+ form use to assemble a sample request: public, generic data such as a well-known airport code
152
+ (`examples: ["SFO"]`), a date a few weeks ahead or a common product category. Never use a value
153
+ from this session: not the caller's input, the owner's answers or anything the site showed
154
+ this account.
143
155
  - Descriptions, titles, examples and defaults are published and reviewed for private data,
144
156
  and an annotation never declares its contents public. Explain constraints without copying private input
145
157
  or unneeded numeric identifiers; for a nonnegative safe integer,
@@ -20,8 +20,11 @@ const failures = [
20
20
  export default defineOperation({
21
21
  name: "set_departure",
22
22
  input: Schema.Struct({
23
- date: DateOnly.annotations({ description: "Departure date, YYYY-MM-DD" }),
24
- cabin: Cabin.annotations({ description: "Cabin class to search" }),
23
+ date: DateOnly.annotations({
24
+ description: "Departure date, YYYY-MM-DD",
25
+ examples: ["2026-11-14"],
26
+ }),
27
+ cabin: Cabin.annotations({ description: "Cabin class to search", examples: ["economy"] }),
25
28
  }),
26
29
  output: Schema.Struct({
27
30
  date: DateOnly.annotations({ description: "Departure date the form now holds, YYYY-MM-DD" }),
@@ -23,8 +23,11 @@ export default defineOperation(
23
23
  {
24
24
  name: "set_departure",
25
25
  input: Schema.Struct({
26
- date: DateOnly.annotations({ description: "Departure date, YYYY-MM-DD" }),
27
- cabin: Cabin.annotations({ description: "Cabin class to search" }),
26
+ date: DateOnly.annotations({
27
+ description: "Departure date, YYYY-MM-DD",
28
+ examples: ["2026-11-14"],
29
+ }),
30
+ cabin: Cabin.annotations({ description: "Cabin class to search", examples: ["economy"] }),
28
31
  }),
29
32
  output: Schema.Struct({
30
33
  date: DateOnly.annotations({ description: "Departure date the form now holds, YYYY-MM-DD" }),
@@ -9,11 +9,11 @@ export declare const pickTravelDate: import("../../src/runtime/kernel-operation.
9
9
  }>;
10
10
  declare const _default: import("../../src/runtime/kernel-operation.js").KernelOperation<{
11
11
  readonly name: string;
12
- readonly mimeType: string;
13
- readonly contentBase64: string;
12
+ readonly mime_type: string;
13
+ readonly content_base64: string;
14
14
  }, {
15
- readonly contentBase64: string;
16
- readonly mimeType: string;
15
+ readonly content_base64: string;
16
+ readonly mime_type: string;
17
17
  readonly name: string;
18
18
  }, {
19
19
  readonly name: string;
@@ -59,10 +59,10 @@ export default defineOperation({
59
59
  name: Schema.NonEmptyString.annotations({
60
60
  description: "File name for the document, with its extension",
61
61
  }),
62
- mimeType: Schema.NonEmptyString.annotations({
62
+ mime_type: Schema.NonEmptyString.annotations({
63
63
  description: "The document's media type, such as application/pdf",
64
64
  }),
65
- contentBase64: Schema.String.annotations({ description: "The document's bytes, base64" }),
65
+ content_base64: Schema.String.annotations({ description: "The document's bytes, base64" }),
66
66
  }),
67
67
  output: Schema.Struct({
68
68
  name: Schema.String.annotations({ description: "Name of the file the field now holds" }),
@@ -79,8 +79,8 @@ export default defineOperation({
79
79
  await field.setInputFiles(
80
80
  {
81
81
  name: ${JSON.stringify(input.name)},
82
- mimeType: ${JSON.stringify(input.mimeType)},
83
- buffer: Buffer.from(${JSON.stringify(input.contentBase64)}, "base64"),
82
+ mimeType: ${JSON.stringify(input.mime_type)},
83
+ buffer: Buffer.from(${JSON.stringify(input.content_base64)}, "base64"),
84
84
  },
85
85
  { timeout: 30000 },
86
86
  );
@@ -95,7 +95,7 @@ export default defineOperation({
95
95
  if ("failure" in result)
96
96
  throw new errors.OperationFailure(result.failure, { dispatch: "not_sent" });
97
97
  const file = result.files[0];
98
- const size = Buffer.from(input.contentBase64, "base64").byteLength;
98
+ const size = Buffer.from(input.content_base64, "base64").byteLength;
99
99
  // Selection is not proof the site accepted the upload; this reads back only the choice.
100
100
  if (result.files.length !== 1 || file?.name !== input.name || file.size !== size)
101
101
  throw new errors.OperationFailure("The chosen file did not read back", { dispatch: "sent" });
@@ -76,10 +76,10 @@ export default defineOperation(
76
76
  name: Schema.NonEmptyString.annotations({
77
77
  description: "File name for the document, with its extension",
78
78
  }),
79
- mimeType: Schema.NonEmptyString.annotations({
79
+ mime_type: Schema.NonEmptyString.annotations({
80
80
  description: "The document's media type, such as application/pdf",
81
81
  }),
82
- contentBase64: Schema.String.annotations({ description: "The document's bytes, base64" }),
82
+ content_base64: Schema.String.annotations({ description: "The document's bytes, base64" }),
83
83
  }),
84
84
  output: Schema.Struct({
85
85
  name: Schema.String.annotations({ description: "Name of the file the field now holds" }),
@@ -97,8 +97,8 @@ export default defineOperation(
97
97
  await field.setInputFiles(
98
98
  {
99
99
  name: ${JSON.stringify(input.name)},
100
- mimeType: ${JSON.stringify(input.mimeType)},
101
- buffer: Buffer.from(${JSON.stringify(input.contentBase64)}, "base64"),
100
+ mimeType: ${JSON.stringify(input.mime_type)},
101
+ buffer: Buffer.from(${JSON.stringify(input.content_base64)}, "base64"),
102
102
  },
103
103
  { timeout: 30000 },
104
104
  );
@@ -118,7 +118,7 @@ export default defineOperation(
118
118
  if ("failure" in result)
119
119
  throw new errors.OperationFailure(result.failure, { dispatch: "not_sent" });
120
120
  const file = result.files[0];
121
- const size = Buffer.from(input.contentBase64, "base64").byteLength;
121
+ const size = Buffer.from(input.content_base64, "base64").byteLength;
122
122
  // Selection is not proof the site accepted the upload; this reads back only the choice.
123
123
  if (result.files.length !== 1 || file?.name !== input.name || file.size !== size)
124
124
  throw new errors.OperationFailure("The chosen file did not read back", { dispatch: "sent" });
@@ -5,8 +5,8 @@ declare const _default: import("../../src/runtime/kernel-operation.js").KernelOp
5
5
  readonly key: string;
6
6
  readonly query: string;
7
7
  }, {
8
- readonly selectedKey: string;
8
+ readonly selected_key: string;
9
9
  }, {
10
- readonly selectedKey: string;
10
+ readonly selected_key: string;
11
11
  }>;
12
12
  export default _default;
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "effect";
2
2
  import { defineOperation } from "../../src/browser/index.js";
3
- const Picked = Schema.Union(Schema.Struct({ selectedKey: Schema.NonEmptyString }), Schema.Struct({
3
+ const Picked = Schema.Union(Schema.Struct({ selected_key: Schema.NonEmptyString }), Schema.Struct({
4
4
  failure: Schema.Literal("query_mismatch", "option_identity_mismatch", "committed_key_mismatch"),
5
5
  }));
6
6
  // These roles, names and data attributes describe one synthetic site's observed picker.
@@ -14,7 +14,7 @@ export default defineOperation({
14
14
  }),
15
15
  }),
16
16
  output: Schema.Struct({
17
- selectedKey: Schema.NonEmptyString.annotations({
17
+ selected_key: Schema.NonEmptyString.annotations({
18
18
  description: "Catalog key the page now shows as selected",
19
19
  }),
20
20
  }),
@@ -45,7 +45,7 @@ export default defineOperation({
45
45
  const committed = page.getByRole("textbox", { name: "Selected catalog key", exact: true });
46
46
  const until = Date.now() + 30000;
47
47
  while (Date.now() < until) {
48
- if ((await committed.inputValue({ timeout: 1000 })) === key) return { selectedKey: key };
48
+ if ((await committed.inputValue({ timeout: 1000 })) === key) return { selected_key: key };
49
49
  await page.waitForTimeout(100);
50
50
  }
51
51
  return { failure: "committed_key_mismatch" };
@@ -2,7 +2,7 @@ import { Schema } from "effect";
2
2
  import { defineOperation } from "../../src/browser/index.js";
3
3
 
4
4
  const Picked = Schema.Union(
5
- Schema.Struct({ selectedKey: Schema.NonEmptyString }),
5
+ Schema.Struct({ selected_key: Schema.NonEmptyString }),
6
6
  Schema.Struct({
7
7
  failure: Schema.Literal("query_mismatch", "option_identity_mismatch", "committed_key_mismatch"),
8
8
  }),
@@ -20,7 +20,7 @@ export default defineOperation(
20
20
  }),
21
21
  }),
22
22
  output: Schema.Struct({
23
- selectedKey: Schema.NonEmptyString.annotations({
23
+ selected_key: Schema.NonEmptyString.annotations({
24
24
  description: "Catalog key the page now shows as selected",
25
25
  }),
26
26
  }),
@@ -52,7 +52,7 @@ export default defineOperation(
52
52
  const committed = page.getByRole("textbox", { name: "Selected catalog key", exact: true });
53
53
  const until = Date.now() + 30000;
54
54
  while (Date.now() < until) {
55
- if ((await committed.inputValue({ timeout: 1000 })) === key) return { selectedKey: key };
55
+ if ((await committed.inputValue({ timeout: 1000 })) === key) return { selected_key: key };
56
56
  await page.waitForTimeout(100);
57
57
  }
58
58
  return { failure: "committed_key_mismatch" };
@@ -1,7 +1,7 @@
1
1
  declare const _default: import("../../src/runtime/kernel-operation.js").KernelOperation<{
2
- readonly invoiceId: string;
2
+ readonly invoice_id: string;
3
3
  }, {
4
- readonly invoiceId: string;
4
+ readonly invoice_id: string;
5
5
  }, {
6
6
  readonly deleted: boolean;
7
7
  }, {
@@ -7,7 +7,7 @@ const InvoiceId = Schema.String.pipe(Schema.pattern(/^[A-Za-z0-9_-]{1,100}$/));
7
7
  export default defineOperation({
8
8
  name: "delete_invoice",
9
9
  input: Schema.Struct({
10
- invoiceId: InvoiceId.annotations({ description: "ID of the invoice to delete" }),
10
+ invoice_id: InvoiceId.annotations({ description: "ID of the invoice to delete" }),
11
11
  }),
12
12
  output: Schema.Struct({
13
13
  deleted: Schema.Boolean.annotations({
@@ -18,7 +18,7 @@ export default defineOperation({
18
18
  const raised = await kernel.browsers.playwright.execute(sessionId, {
19
19
  timeout_sec: 30,
20
20
  code: `
21
- const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoiceId)}, { exact: true }) });
21
+ const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoice_id)}, { exact: true }) });
22
22
  if ((await row.count()) !== 1) return { failure: "invoice_missing" };
23
23
  const shown = new Promise((resolve) => page.once("dialog", (dialog) => {
24
24
  globalThis.dialog = dialog;
@@ -53,7 +53,7 @@ export default defineOperation({
53
53
  ? `await globalThis.dialog.accept(${JSON.stringify(decision.promptText ?? "")});`
54
54
  : "await globalThis.dialog.dismiss();"}
55
55
  delete globalThis.dialog;
56
- const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoiceId)}, { exact: true }) });
56
+ const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoice_id)}, { exact: true }) });
57
57
  // Read the result back: the row is gone only if the site deleted it.
58
58
  await row.waitFor({ state: ${JSON.stringify(decision.choice === "accept" ? "detached" : "visible")}, timeout: 10000 });
59
59
  return { deleted: (await row.count()) === 0 };
@@ -10,7 +10,7 @@ export default defineOperation(
10
10
  {
11
11
  name: "delete_invoice",
12
12
  input: Schema.Struct({
13
- invoiceId: InvoiceId.annotations({ description: "ID of the invoice to delete" }),
13
+ invoice_id: InvoiceId.annotations({ description: "ID of the invoice to delete" }),
14
14
  }),
15
15
  output: Schema.Struct({
16
16
  deleted: Schema.Boolean.annotations({
@@ -22,7 +22,7 @@ export default defineOperation(
22
22
  const raised = await kernel.browsers.playwright.execute(sessionId, {
23
23
  timeout_sec: 30,
24
24
  code: `
25
- const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoiceId)}, { exact: true }) });
25
+ const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoice_id)}, { exact: true }) });
26
26
  if ((await row.count()) !== 1) return { failure: "invoice_missing" };
27
27
  const shown = new Promise((resolve) => page.once("dialog", (dialog) => {
28
28
  globalThis.dialog = dialog;
@@ -64,7 +64,7 @@ export default defineOperation(
64
64
  : "await globalThis.dialog.dismiss();"
65
65
  }
66
66
  delete globalThis.dialog;
67
- const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoiceId)}, { exact: true }) });
67
+ const row = page.getByRole("row").filter({ has: page.getByText(${JSON.stringify(input.invoice_id)}, { exact: true }) });
68
68
  // Read the result back: the row is gone only if the site deleted it.
69
69
  await row.waitFor({ state: ${JSON.stringify(decision.choice === "accept" ? "detached" : "visible")}, timeout: 10000 });
70
70
  return { deleted: (await row.count()) === 0 };
@@ -1,12 +1,12 @@
1
1
  export declare const detailNavigation: import("../../src/runtime/kernel-operation.js").KernelOperation<{
2
- readonly recordId: string;
2
+ readonly record_id: string;
3
3
  }, {
4
- readonly recordId: string;
4
+ readonly record_id: string;
5
5
  }, {
6
- readonly recordId: string;
6
+ readonly record_id: string;
7
7
  readonly title: string;
8
8
  }, {
9
- readonly recordId: string;
9
+ readonly record_id: string;
10
10
  readonly title: string;
11
11
  }>;
12
12
  declare const _default: import("../../src/runtime/kernel-operation.js").KernelOperation<{}, {}, {
@@ -9,16 +9,19 @@ const Detail = Schema.Union(Schema.Struct({ title: Schema.NonEmptyString }), Sch
9
9
  export const detailNavigation = defineOperation({
10
10
  name: "read_record_detail",
11
11
  input: Schema.Struct({
12
- recordId: RecordId.annotations({ description: "ID of the record to read, as in its URL" }),
12
+ record_id: RecordId.annotations({
13
+ description: "ID of the record to read, as in its URL",
14
+ examples: ["record_42"],
15
+ }),
13
16
  }),
14
17
  output: Schema.Struct({
15
- recordId: RecordId.annotations({ description: "ID of the record read" }),
18
+ record_id: RecordId.annotations({ description: "ID of the record read" }),
16
19
  title: Schema.NonEmptyString.annotations({ description: "The record's title" }),
17
20
  }),
18
21
  }, async ({ kernel, sessionId, siteOrigin, siteDomain, input, errors }) => {
19
22
  if (siteOrigin === undefined)
20
23
  throw new errors.OperationFailure("No site origin for a live run", { dispatch: "not_sent" });
21
- const target = new URL(`/records/${input.recordId}`, siteOrigin);
24
+ const target = new URL(`/records/${input.record_id}`, siteOrigin);
22
25
  const answer = await kernel.browsers.playwright.execute(sessionId, {
23
26
  timeout_sec: 90,
24
27
  code: `
@@ -28,7 +31,7 @@ export const detailNavigation = defineOperation({
28
31
  const siteDomain = ${JSON.stringify(siteDomain ?? null)};
29
32
  const onSite = (url) => siteDomain === null ? url.origin === ${JSON.stringify(siteOrigin)}
30
33
  : url.protocol === "https:" && (url.hostname === siteDomain || url.hostname.endsWith("." + siteDomain));
31
- const recordId = ${JSON.stringify(input.recordId)};
34
+ const recordId = ${JSON.stringify(input.record_id)};
32
35
  const detail = page.getByRole("region", { name: "Record details", exact: true });
33
36
  const interstitial = page.getByRole("region", { name: "Continue to record", exact: true });
34
37
  const proceed = interstitial.getByRole("button", { name: "Continue", exact: true });
@@ -81,7 +84,7 @@ export const detailNavigation = defineOperation({
81
84
  const result = Schema.decodeUnknownSync(Detail)(answer.result);
82
85
  if ("failure" in result)
83
86
  throw new errors.OperationFailure(result.failure);
84
- return { recordId: input.recordId, title: result.title };
87
+ return { record_id: input.record_id, title: result.title };
85
88
  });
86
89
  // A bounded first-page read. A fast exploration load does not remove the readiness wait.
87
90
  export default defineOperation({
@@ -20,17 +20,20 @@ export const detailNavigation = defineOperation(
20
20
  {
21
21
  name: "read_record_detail",
22
22
  input: Schema.Struct({
23
- recordId: RecordId.annotations({ description: "ID of the record to read, as in its URL" }),
23
+ record_id: RecordId.annotations({
24
+ description: "ID of the record to read, as in its URL",
25
+ examples: ["record_42"],
26
+ }),
24
27
  }),
25
28
  output: Schema.Struct({
26
- recordId: RecordId.annotations({ description: "ID of the record read" }),
29
+ record_id: RecordId.annotations({ description: "ID of the record read" }),
27
30
  title: Schema.NonEmptyString.annotations({ description: "The record's title" }),
28
31
  }),
29
32
  },
30
33
  async ({ kernel, sessionId, siteOrigin, siteDomain, input, errors }) => {
31
34
  if (siteOrigin === undefined)
32
35
  throw new errors.OperationFailure("No site origin for a live run", { dispatch: "not_sent" });
33
- const target = new URL(`/records/${input.recordId}`, siteOrigin);
36
+ const target = new URL(`/records/${input.record_id}`, siteOrigin);
34
37
  const answer = await kernel.browsers.playwright.execute(sessionId, {
35
38
  timeout_sec: 90,
36
39
  code: `
@@ -40,7 +43,7 @@ export const detailNavigation = defineOperation(
40
43
  const siteDomain = ${JSON.stringify(siteDomain ?? null)};
41
44
  const onSite = (url) => siteDomain === null ? url.origin === ${JSON.stringify(siteOrigin)}
42
45
  : url.protocol === "https:" && (url.hostname === siteDomain || url.hostname.endsWith("." + siteDomain));
43
- const recordId = ${JSON.stringify(input.recordId)};
46
+ const recordId = ${JSON.stringify(input.record_id)};
44
47
  const detail = page.getByRole("region", { name: "Record details", exact: true });
45
48
  const interstitial = page.getByRole("region", { name: "Continue to record", exact: true });
46
49
  const proceed = interstitial.getByRole("button", { name: "Continue", exact: true });
@@ -92,7 +95,7 @@ export const detailNavigation = defineOperation(
92
95
  throw new errors.OperationFailure(String(answer.error), { stderr: answer.stderr });
93
96
  const result = Schema.decodeUnknownSync(Detail)(answer.result);
94
97
  if ("failure" in result) throw new errors.OperationFailure(result.failure);
95
- return { recordId: input.recordId, title: result.title };
98
+ return { record_id: input.record_id, title: result.title };
96
99
  },
97
100
  );
98
101
 
@@ -5,7 +5,7 @@ declare const _default: import("../../src/runtime/kernel-operation.js").KernelOp
5
5
  }, {
6
6
  readonly invoices: readonly {
7
7
  readonly id: string;
8
- readonly totalMinor: number;
8
+ readonly total_minor: number;
9
9
  readonly currency: "USD";
10
10
  }[];
11
11
  readonly complete: boolean;
@@ -14,7 +14,7 @@ declare const _default: import("../../src/runtime/kernel-operation.js").KernelOp
14
14
  readonly invoices: readonly {
15
15
  readonly currency: "USD";
16
16
  readonly id: string;
17
- readonly totalMinor: number;
17
+ readonly total_minor: number;
18
18
  }[];
19
19
  }>;
20
20
  export default _default;
@@ -2,7 +2,7 @@ import { Schema } from "effect";
2
2
  import { defineOperation } from "../../src/browser/index.js";
3
3
  const Invoice = Schema.Struct({
4
4
  id: Schema.NonEmptyString.annotations({ description: "The site's invoice ID" }),
5
- totalMinor: Schema.Int.annotations({ description: "Invoice total in cents" }),
5
+ total_minor: Schema.Int.annotations({ description: "Invoice total in minor units (cents)" }),
6
6
  currency: Schema.Literal("USD").annotations({ description: "Currency of the total" }),
7
7
  });
8
8
  const Body = Schema.Struct({
@@ -3,7 +3,7 @@ import { defineOperation } from "../../src/browser/index.js";
3
3
 
4
4
  const Invoice = Schema.Struct({
5
5
  id: Schema.NonEmptyString.annotations({ description: "The site's invoice ID" }),
6
- totalMinor: Schema.Int.annotations({ description: "Invoice total in cents" }),
6
+ total_minor: Schema.Int.annotations({ description: "Invoice total in minor units (cents)" }),
7
7
  currency: Schema.Literal("USD").annotations({ description: "Currency of the total" }),
8
8
  });
9
9
  const Body = Schema.Struct({
@@ -2,48 +2,48 @@ import { Schema } from "effect";
2
2
  export declare const OrderInput: Schema.Struct<{
3
3
  item: Schema.refine<string, typeof Schema.String>;
4
4
  quantity: Schema.refine<number, typeof Schema.Int>;
5
- giftWrap: Schema.SchemaClass<boolean, boolean, never>;
5
+ gift_wrap: Schema.SchemaClass<boolean, boolean, never>;
6
6
  }>;
7
7
  /** Act step 1: fills the checkout on the site origin page and stops before the commit. */
8
8
  export declare const fillStep: import("../../src/runtime/kernel-operation.js").KernelOperation<{
9
9
  readonly item: string;
10
10
  readonly quantity: number;
11
- readonly giftWrap: boolean;
11
+ readonly gift_wrap: boolean;
12
12
  }, {
13
- readonly giftWrap: boolean;
13
+ readonly gift_wrap: boolean;
14
14
  readonly item: string;
15
15
  readonly quantity: number;
16
16
  }, {
17
- readonly reviewShown: boolean;
17
+ readonly review_shown: boolean;
18
18
  }, {
19
- readonly reviewShown: boolean;
19
+ readonly review_shown: boolean;
20
20
  }>;
21
21
  /** Act step 2: continues on the page step 1 left, commits once and reads the confirmation. */
22
22
  export declare const placeStep: import("../../src/runtime/kernel-operation.js").KernelOperation<{
23
23
  readonly item: string;
24
24
  readonly quantity: number;
25
- readonly giftWrap: boolean;
25
+ readonly gift_wrap: boolean;
26
26
  }, {
27
- readonly giftWrap: boolean;
27
+ readonly gift_wrap: boolean;
28
28
  readonly item: string;
29
29
  readonly quantity: number;
30
30
  }, {
31
- readonly orderNumber: string;
31
+ readonly order_number: string;
32
32
  }, {
33
- readonly orderNumber: string;
33
+ readonly order_number: string;
34
34
  }>;
35
35
  /** The composed script, published without another run: the whole flow from the site origin page. */
36
36
  declare const _default: import("../../src/runtime/kernel-operation.js").KernelOperation<{
37
37
  readonly item: string;
38
38
  readonly quantity: number;
39
- readonly giftWrap: boolean;
39
+ readonly gift_wrap: boolean;
40
40
  }, {
41
- readonly giftWrap: boolean;
41
+ readonly gift_wrap: boolean;
42
42
  readonly item: string;
43
43
  readonly quantity: number;
44
44
  }, {
45
- readonly orderNumber: string;
45
+ readonly order_number: string;
46
46
  }, {
47
- readonly orderNumber: string;
47
+ readonly order_number: string;
48
48
  }>;
49
49
  export default _default;
@@ -11,15 +11,15 @@ export const OrderInput = Schema.Struct({
11
11
  quantity: Schema.Int.pipe(Schema.between(1, 99)).annotations({
12
12
  description: "How many to order, 1 to 99",
13
13
  }),
14
- giftWrap: Schema.Boolean.annotations({ description: "Whether to add gift wrap" }),
14
+ gift_wrap: Schema.Boolean.annotations({ description: "Whether to add gift wrap" }),
15
15
  });
16
16
  const Placed = Schema.Struct({
17
- orderNumber: Schema.NonEmptyString.annotations({
17
+ order_number: Schema.NonEmptyString.annotations({
18
18
  description: "Order number from the confirmation",
19
19
  }),
20
20
  });
21
- const Filled = Schema.Union(Schema.Struct({ reviewShown: Schema.Literal(true) }), Schema.Struct({ failure: Schema.Literal("checkout_changed") }));
22
- const Confirmed = Schema.Union(Schema.Struct({ orderNumber: Schema.NonEmptyString }), Schema.Struct({ failure: Schema.Literal("review_missing", "not_confirmed") }));
21
+ const Filled = Schema.Union(Schema.Struct({ review_shown: Schema.Literal(true) }), Schema.Struct({ failure: Schema.Literal("checkout_changed") }));
22
+ const Confirmed = Schema.Union(Schema.Struct({ order_number: Schema.NonEmptyString }), Schema.Struct({ failure: Schema.Literal("review_missing", "not_confirmed") }));
23
23
  // The act steps and the composed script share these calls, so the published script repeats
24
24
  // exactly what the session did.
25
25
  /** From the site origin page: open the checkout, fill it from the input and stop at the review step. */
@@ -36,10 +36,10 @@ const fillCheckout = async ({ kernel, sessionId, siteOrigin, input, errors }) =>
36
36
  if ((await form.count()) !== 1) return { failure: "checkout_changed" };
37
37
  await form.getByLabel("Item", { exact: true }).fill(input.item, { timeout: 5000 });
38
38
  await form.getByLabel("Quantity", { exact: true }).fill(String(input.quantity), { timeout: 5000 });
39
- await form.getByLabel("Gift wrap", { exact: true }).setChecked(input.giftWrap, { timeout: 5000 });
39
+ await form.getByLabel("Gift wrap", { exact: true }).setChecked(input.gift_wrap, { timeout: 5000 });
40
40
  await form.getByRole("button", { name: "Continue", exact: true }).click({ timeout: 5000 });
41
41
  await page.getByRole("button", { name: "Place order", exact: true }).waitFor({ timeout: 10000 });
42
- return { reviewShown: true };
42
+ return { review_shown: true };
43
43
  `,
44
44
  });
45
45
  if (!answer.success)
@@ -63,7 +63,7 @@ const placeAndConfirm = async ({ kernel, sessionId, errors, verified, enteringCo
63
63
  const confirmation = page.getByRole("status", { name: "Order confirmation", exact: true });
64
64
  try { await confirmation.waitFor({ timeout: 15000 }); } catch { return { failure: "not_confirmed" }; }
65
65
  const number = /^Order (ORD-[0-9]+)/.exec(await confirmation.innerText())?.[1];
66
- return number === undefined ? { failure: "not_confirmed" } : { orderNumber: number };
66
+ return number === undefined ? { failure: "not_confirmed" } : { order_number: number };
67
67
  `,
68
68
  });
69
69
  // A failure after the click leaves the write uncertain. Nothing here resubmits it.
@@ -83,11 +83,11 @@ export const fillStep = defineOperation({
83
83
  name: "fill_checkout",
84
84
  input: OrderInput,
85
85
  output: Schema.Struct({
86
- reviewShown: Schema.Boolean.annotations({ description: "True once the review step shows" }),
86
+ review_shown: Schema.Boolean.annotations({ description: "True once the review step shows" }),
87
87
  }),
88
88
  }, async (context) => {
89
89
  await fillCheckout(context);
90
- return { reviewShown: true };
90
+ return { review_shown: true };
91
91
  });
92
92
  /** Act step 2: continues on the page step 1 left, commits once and reads the confirmation. */
93
93
  export const placeStep = defineOperation({ name: "place_order", input: OrderInput, output: Placed }, placeAndConfirm);
@@ -13,20 +13,20 @@ export const OrderInput = Schema.Struct({
13
13
  quantity: Schema.Int.pipe(Schema.between(1, 99)).annotations({
14
14
  description: "How many to order, 1 to 99",
15
15
  }),
16
- giftWrap: Schema.Boolean.annotations({ description: "Whether to add gift wrap" }),
16
+ gift_wrap: Schema.Boolean.annotations({ description: "Whether to add gift wrap" }),
17
17
  });
18
18
  type OrderInput = typeof OrderInput.Type;
19
19
  const Placed = Schema.Struct({
20
- orderNumber: Schema.NonEmptyString.annotations({
20
+ order_number: Schema.NonEmptyString.annotations({
21
21
  description: "Order number from the confirmation",
22
22
  }),
23
23
  });
24
24
  const Filled = Schema.Union(
25
- Schema.Struct({ reviewShown: Schema.Literal(true) }),
25
+ Schema.Struct({ review_shown: Schema.Literal(true) }),
26
26
  Schema.Struct({ failure: Schema.Literal("checkout_changed") }),
27
27
  );
28
28
  const Confirmed = Schema.Union(
29
- Schema.Struct({ orderNumber: Schema.NonEmptyString }),
29
+ Schema.Struct({ order_number: Schema.NonEmptyString }),
30
30
  Schema.Struct({ failure: Schema.Literal("review_missing", "not_confirmed") }),
31
31
  );
32
32
  type Context = KernelOperationContext<OrderInput>;
@@ -48,10 +48,10 @@ const fillCheckout = async ({ kernel, sessionId, siteOrigin, input, errors }: Co
48
48
  if ((await form.count()) !== 1) return { failure: "checkout_changed" };
49
49
  await form.getByLabel("Item", { exact: true }).fill(input.item, { timeout: 5000 });
50
50
  await form.getByLabel("Quantity", { exact: true }).fill(String(input.quantity), { timeout: 5000 });
51
- await form.getByLabel("Gift wrap", { exact: true }).setChecked(input.giftWrap, { timeout: 5000 });
51
+ await form.getByLabel("Gift wrap", { exact: true }).setChecked(input.gift_wrap, { timeout: 5000 });
52
52
  await form.getByRole("button", { name: "Continue", exact: true }).click({ timeout: 5000 });
53
53
  await page.getByRole("button", { name: "Place order", exact: true }).waitFor({ timeout: 10000 });
54
- return { reviewShown: true };
54
+ return { review_shown: true };
55
55
  `,
56
56
  });
57
57
  if (!answer.success)
@@ -82,7 +82,7 @@ const placeAndConfirm = async ({
82
82
  const confirmation = page.getByRole("status", { name: "Order confirmation", exact: true });
83
83
  try { await confirmation.waitFor({ timeout: 15000 }); } catch { return { failure: "not_confirmed" }; }
84
84
  const number = /^Order (ORD-[0-9]+)/.exec(await confirmation.innerText())?.[1];
85
- return number === undefined ? { failure: "not_confirmed" } : { orderNumber: number };
85
+ return number === undefined ? { failure: "not_confirmed" } : { order_number: number };
86
86
  `,
87
87
  });
88
88
  // A failure after the click leaves the write uncertain. Nothing here resubmits it.
@@ -104,12 +104,12 @@ export const fillStep = defineOperation(
104
104
  name: "fill_checkout",
105
105
  input: OrderInput,
106
106
  output: Schema.Struct({
107
- reviewShown: Schema.Boolean.annotations({ description: "True once the review step shows" }),
107
+ review_shown: Schema.Boolean.annotations({ description: "True once the review step shows" }),
108
108
  }),
109
109
  },
110
110
  async (context) => {
111
111
  await fillCheckout(context);
112
- return { reviewShown: true };
112
+ return { review_shown: true };
113
113
  },
114
114
  );
115
115
 
@@ -10,7 +10,8 @@ export declare class UpstreamPolicySlotInvalid extends UpstreamPolicySlotInvalid
10
10
  /**
11
11
  * Puts Pomerado's policy in the upstream policy's one slot. An adapter calls it when it is built,
12
12
  * so a policy file without the slot stops startup instead of Guardian reviewing without
13
- * Pomerado's policy.
13
+ * Pomerado's policy. A leading HTML comment is dropped first, so the file's licence notice is
14
+ * neither sent to the model nor counted as a slot.
14
15
  */
15
16
  export declare const withTenantPolicy: (upstreamPolicy: string, tenantPolicy: string) => string;
16
17
  export {};