otto-intel-mcp 0.1.2 → 0.1.3

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 (51) hide show
  1. package/README.md +4 -2
  2. package/dist/adapter/cdp-signer.d.ts +44 -5
  3. package/dist/adapter/cdp-signer.js +168 -18
  4. package/dist/adapter/evm-call-failure.d.ts +29 -0
  5. package/dist/adapter/evm-call-failure.js +109 -0
  6. package/dist/adapter/refusal.d.ts +1 -1
  7. package/dist/adapter/refusal.js +13 -0
  8. package/dist/adapter/route-simulator.d.ts +91 -0
  9. package/dist/adapter/route-simulator.js +143 -0
  10. package/dist/executable-equities.d.ts +55 -0
  11. package/dist/executable-equities.js +116 -0
  12. package/dist/executable-yield-markets.d.ts +261 -0
  13. package/dist/executable-yield-markets.js +154 -0
  14. package/dist/execution-delegated-definition.d.ts +1 -0
  15. package/dist/execution-delegated-definition.js +13 -2
  16. package/dist/execution-delegation-admin-definition.d.ts +126 -5
  17. package/dist/execution-delegation-admin-definition.js +154 -5
  18. package/dist/execution-delegation-admin.d.ts +48 -2
  19. package/dist/execution-delegation-admin.js +314 -12
  20. package/dist/execution-delegation-cap-store.d.ts +369 -0
  21. package/dist/execution-delegation-cap-store.js +1083 -0
  22. package/dist/execution-delegation-policy.d.ts +153 -6
  23. package/dist/execution-delegation-policy.js +260 -16
  24. package/dist/execution-delegation.d.ts +35 -0
  25. package/dist/execution-delegation.js +224 -9
  26. package/dist/execution-errors.d.ts +1 -1
  27. package/dist/execution-errors.js +98 -0
  28. package/dist/execution-index.d.ts +3 -2
  29. package/dist/execution-index.js +3 -2
  30. package/dist/execution-registration.d.ts +51 -2
  31. package/dist/execution-registration.js +45 -2
  32. package/dist/execution-tools.d.ts +44 -1
  33. package/dist/execution-tools.js +157 -13
  34. package/dist/lifi-execution-client.d.ts +6 -0
  35. package/dist/lifi-execution-client.js +3 -0
  36. package/dist/stock-buy-definition.d.ts +338 -0
  37. package/dist/stock-buy-definition.js +127 -0
  38. package/dist/stock-buy-oracle.d.ts +8 -0
  39. package/dist/stock-buy-oracle.js +22 -0
  40. package/dist/stock-buy.d.ts +17 -0
  41. package/dist/stock-buy.js +164 -0
  42. package/dist/tool-definitions.js +1 -1
  43. package/dist/yield-deposit-definition.d.ts +323 -0
  44. package/dist/yield-deposit-definition.js +121 -0
  45. package/dist/yield-deposit.d.ts +16 -0
  46. package/dist/yield-deposit.js +141 -0
  47. package/dist/yield-withdraw-definition.d.ts +306 -0
  48. package/dist/yield-withdraw-definition.js +88 -0
  49. package/dist/yield-withdraw.d.ts +21 -0
  50. package/dist/yield-withdraw.js +120 -0
  51. package/package.json +28 -4
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Server-owned yield execution registry.
3
+ *
4
+ * The dApp's server route and TEA import the exact same records. Discovery can
5
+ * attach APY data to a record, but it cannot create or mutate execution
6
+ * eligibility. The canonical commitment is server-only (both consumers run in
7
+ * Node) and covers the complete registry record, including nested fields.
8
+ */
9
+ import { createHash } from 'node:crypto';
10
+ function deepFreeze(value) {
11
+ if (value && typeof value === 'object' && !Object.isFrozen(value)) {
12
+ for (const nested of Object.values(value))
13
+ deepFreeze(nested);
14
+ Object.freeze(value);
15
+ }
16
+ return value;
17
+ }
18
+ export const BASE_USDC_AAVE_V3_MARKET = deepFreeze({
19
+ id: 'base-usdc-aave-v3',
20
+ venue: 'AAVE V3',
21
+ protocol: 'AAVE',
22
+ chainId: 8453,
23
+ chainSlug: 'base',
24
+ asset: {
25
+ symbol: 'USDC',
26
+ group: 'USDC',
27
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
28
+ decimals: 6,
29
+ },
30
+ protocolTarget: '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5',
31
+ vaultAddress: '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5',
32
+ nativeValue: '0',
33
+ builder: 'aave-native',
34
+ selectors: {
35
+ approve: '0x095ea7b3',
36
+ supply: '0x617ba037',
37
+ withdraw: '0x69328dec',
38
+ },
39
+ // An existing exact allowance lets the SDK omit approve. No other leg is valid.
40
+ allowedCallSequences: {
41
+ deposit: [['approve', 'supply'], ['supply']],
42
+ withdraw: [['withdraw']],
43
+ },
44
+ safeBinding: {
45
+ executionOwner: 'SAFE',
46
+ depositReceiver: 'SAFE',
47
+ withdrawReceiver: 'SAFE',
48
+ },
49
+ discoveryMarketId: 'aave:8453:0xa238dd80c259a72e81d7e4664a9801593f98d1c5:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
50
+ });
51
+ export const BASE_USDC_MORPHO_GAUNTLET_PRIME_MARKET = deepFreeze({
52
+ id: 'base-usdc-morpho-gauntlet-prime',
53
+ venue: 'MORPHO · GAUNTLET USDC PRIME',
54
+ protocol: 'MORPHO',
55
+ chainId: 8453,
56
+ chainSlug: 'base',
57
+ asset: {
58
+ symbol: 'USDC',
59
+ group: 'USDC',
60
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
61
+ decimals: 6,
62
+ },
63
+ protocolTarget: '0xeE8F4eC5672F09119b96Ab6fB59C27E1b7e44b61',
64
+ vaultAddress: '0xeE8F4eC5672F09119b96Ab6fB59C27E1b7e44b61',
65
+ vaultShareDecimals: 18,
66
+ nativeValue: '0',
67
+ builder: 'morpho-native',
68
+ selectors: {
69
+ approve: '0x095ea7b3',
70
+ deposit: '0x6e553f65',
71
+ withdraw: '0xb460af94',
72
+ redeem: '0xba087652',
73
+ },
74
+ allowedCallSequences: {
75
+ deposit: [['approve', 'deposit'], ['deposit']],
76
+ withdraw: [['withdraw'], ['redeem']],
77
+ },
78
+ safeBinding: {
79
+ executionOwner: 'SAFE',
80
+ depositReceiver: 'SAFE',
81
+ withdrawReceiver: 'SAFE',
82
+ },
83
+ discoveryMarketId: 'morpho:8453:0xee8f4ec5672f09119b96ab6fb59c27e1b7e44b61:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
84
+ });
85
+ export const BASE_USDC_MORPHO_STEAKHOUSE_PRIME_MARKET = deepFreeze({
86
+ id: 'base-usdc-morpho-steakhouse-prime',
87
+ venue: 'MORPHO · STEAKHOUSE PRIME USDC',
88
+ protocol: 'MORPHO',
89
+ chainId: 8453,
90
+ chainSlug: 'base',
91
+ asset: {
92
+ symbol: 'USDC',
93
+ group: 'USDC',
94
+ address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
95
+ decimals: 6,
96
+ },
97
+ protocolTarget: '0xBEEFE94c8aD530842bfE7d8B397938fFc1cb83b2',
98
+ vaultAddress: '0xBEEFE94c8aD530842bfE7d8B397938fFc1cb83b2',
99
+ vaultShareDecimals: 18,
100
+ nativeValue: '0',
101
+ builder: 'morpho-native',
102
+ selectors: {
103
+ approve: '0x095ea7b3',
104
+ deposit: '0x6e553f65',
105
+ withdraw: '0xb460af94',
106
+ redeem: '0xba087652',
107
+ },
108
+ allowedCallSequences: {
109
+ deposit: [['approve', 'deposit'], ['deposit']],
110
+ withdraw: [['withdraw'], ['redeem']],
111
+ },
112
+ safeBinding: {
113
+ executionOwner: 'SAFE',
114
+ depositReceiver: 'SAFE',
115
+ withdrawReceiver: 'SAFE',
116
+ },
117
+ discoveryMarketId: 'morpho:8453:0xbeefe94c8ad530842bfe7d8b397938ffc1cb83b2:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
118
+ });
119
+ export const EXECUTABLE_YIELD_MARKETS = deepFreeze([
120
+ BASE_USDC_AAVE_V3_MARKET,
121
+ BASE_USDC_MORPHO_GAUNTLET_PRIME_MARKET,
122
+ BASE_USDC_MORPHO_STEAKHOUSE_PRIME_MARKET,
123
+ ]);
124
+ function canonicalJson(value) {
125
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') {
126
+ return JSON.stringify(value);
127
+ }
128
+ if (typeof value === 'number') {
129
+ if (!Number.isFinite(value))
130
+ throw new Error('executable yield registry contains a non-finite number');
131
+ return JSON.stringify(value);
132
+ }
133
+ if (Array.isArray(value))
134
+ return `[${value.map(canonicalJson).join(',')}]`;
135
+ if (typeof value === 'object') {
136
+ const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
137
+ return `{${entries
138
+ .map(([key, nested]) => `${JSON.stringify(key)}:${canonicalJson(nested)}`)
139
+ .join(',')}}`;
140
+ }
141
+ throw new Error('executable yield registry contains a non-canonical value');
142
+ }
143
+ /** SHA-256 commitment over every enumerable field in the complete, canonical registry record. */
144
+ export function getExecutableYieldMarketCommitment(market) {
145
+ const canonical = canonicalJson(market);
146
+ const digest = createHash('sha256')
147
+ .update(`otto:executable-yield-market:v1:${canonical}`, 'utf8')
148
+ .digest('hex');
149
+ return `sha256:${digest}`;
150
+ }
151
+ export function getExecutableYieldMarket(marketId) {
152
+ return EXECUTABLE_YIELD_MARKETS.find((market) => market.id === marketId) ?? null;
153
+ }
154
+ //# sourceMappingURL=executable-yield-markets.js.map
@@ -129,6 +129,7 @@ export declare const DELEGATED_SEND_RESULT_SCHEMA: z.ZodObject<{
129
129
  policy_name: z.ZodString;
130
130
  rules_digest: z.ZodString;
131
131
  per_swap_cap_usd: z.ZodLiteral<5000>;
132
+ user_cap_usd: z.ZodNumber;
132
133
  }, z.core.$strict>;
133
134
  delegation: z.ZodObject<{
134
135
  expires_at: z.ZodString;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { z } from 'zod';
8
8
  import { EXECUTION_ENVELOPE_SCHEMA, PREPARE_SWAP_INPUT_SCHEMA, } from './execution-tool-definitions.js';
9
- import { MODEL_B_PER_SWAP_CAP_USD } from './execution-delegation-policy.js';
9
+ import { MODEL_B_PER_SWAP_CAP_MIN_USD, MODEL_B_PER_SWAP_CAP_USD, } from './execution-delegation-policy.js';
10
10
  export const DELEGATED_EXECUTION_TOOL_NAME = 'otto_submit_under_delegation';
11
11
  /** Per-request caller authentication rides THIS header — never a tool argument (arguments are logged). */
12
12
  export const DELEGATION_AUTH_HEADER = 'x-otto-delegation-auth';
@@ -78,7 +78,18 @@ export const DELEGATED_SEND_RESULT_SCHEMA = z
78
78
  policy_id: z.string(),
79
79
  policy_name: z.string(),
80
80
  rules_digest: z.string().regex(/^[0-9a-f]{64}$/),
81
+ /** The ENGINE's ceiling — the constant in the one shared project policy. Still a literal. */
81
82
  per_swap_cap_usd: z.literal(MODEL_B_PER_SWAP_CAP_USD),
83
+ /**
84
+ * The cap THIS person chose when they minted, enforced by Otto's server on top of the ceiling.
85
+ * A bounded integer rather than a literal, because it is the whole point that it can be lower —
86
+ * but it can never exceed the ceiling, and that bound is here rather than left to the caller.
87
+ */
88
+ user_cap_usd: z
89
+ .number()
90
+ .int()
91
+ .min(MODEL_B_PER_SWAP_CAP_MIN_USD)
92
+ .max(MODEL_B_PER_SWAP_CAP_USD),
82
93
  })
83
94
  .strict(),
84
95
  delegation: z.object({ expires_at: z.string() }).strict(),
@@ -108,7 +119,7 @@ export const DELEGATED_TOOL_ANNOTATIONS = Object.freeze({
108
119
  export const DELEGATED_EXECUTION_TOOL_DEFINITION = Object.freeze({
109
120
  name: DELEGATED_EXECUTION_TOOL_NAME,
110
121
  title: 'Submit an Otto-prepared swap under a CDP end-user delegation',
111
- description: `Submit a verified otto_prepare_swap envelope on Base under the end user's CDP delegation. Arguments: { userId, envelope (the otto_prepare_swap result), prepareInput (the exact otto_prepare_swap request, with slippage.minAmountOut) } — validated strictly AFTER the caller is authenticated, so the listed input schema is intentionally permissive. Server-to-server only: the caller presents Otto's delegation secret in the \`${DELEGATION_AUTH_HEADER}\` request header (never in arguments); a call without it is refused before anything is read. Before any send the server confirms, in this order: the Model-B project policy is installed and reads back by name and rules digest; the user's grant is active past the envelope's valid_until; the account is one of that end user's own CDP accounts as CDP reports them; the envelope passes the 13-check verifier for exactly the request that produced it; the plan is inside the fence (allow-listed input token, reviewed spender, gross at or below the ${MODEL_B_PER_SWAP_CAP_USD} USD per-swap cap). Then the three steps (allowance reset, approval, swap) are submitted in order under the delegation, each waited to a sealed canonical block; a halt clears the allowance and reports the read-back. One delegated plan at a time per user. Coinbase's engine bounds the delegated key to Model-B swap shapes through LI.FI up to the per-swap cap; the receiver binding is Otto's server-side check, and the user can revoke at any time.`,
122
+ description: `Submit a verified otto_prepare_swap envelope on Base under the end user's CDP delegation. Arguments: { userId, envelope (the otto_prepare_swap result), prepareInput (the exact otto_prepare_swap request, with slippage.minAmountOut) } — validated strictly AFTER the caller is authenticated, so the listed input schema is intentionally permissive. Server-to-server only: the caller presents Otto's delegation secret in the \`${DELEGATION_AUTH_HEADER}\` request header (never in arguments); a call without it is refused before anything is read. Before any send the server confirms, in this order: the Model-B project policy is installed and reads back by name and rules digest; the user's grant is active past the envelope's valid_until; the account is one of that end user's own CDP accounts as CDP reports them; the envelope passes the 13-check verifier for exactly the request that produced it; the plan is inside the fence (allow-listed input token, reviewed spender, gross at or below the ${MODEL_B_PER_SWAP_CAP_USD} USD engine ceiling); and the plan is at or below the per-swap cap THIS user chose when they minted, which is recorded against their grant on this server. A delegation with no recorded cap is REFUSED (DELEGATION_CAP_UNRECORDED) rather than defaulted to the ceiling \u2014 mint the permission again to set one. Then the three steps (allowance reset, approval, swap) are submitted in order under the delegation, each waited to a sealed canonical block; a halt clears the allowance and reports the read-back. One delegated plan at a time per user. Coinbase's engine bounds the delegated key to Model-B swap shapes through LI.FI up to the ${MODEL_B_PER_SWAP_CAP_USD} USD ceiling, which is shared by every delegated user and cannot be narrowed per user by the engine; the user's own lower cap and the receiver binding are Otto's server-side checks, and the user can revoke at any time.`,
112
123
  inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
113
124
  strictInputSchema: SUBMIT_UNDER_DELEGATION_INPUT_SCHEMA,
114
125
  outputSchema: DELEGATED_SEND_RESULT_SCHEMA,
@@ -1,6 +1,8 @@
1
1
  /**
2
- * execution-delegation-admin-definition.ts — the three header-authed delegation ADMIN tools (PR-1b, seat ruling
3
- * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`.
2
+ * execution-delegation-admin-definition.ts — the four header-authed delegation ADMIN tools (PR-1b, seat ruling
3
+ * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`, and
4
+ * `otto_delegation_cap` (Founder word `delegate cap choice`, 2026-09-02 — the per-swap cap a person chose,
5
+ * recorded against the grant they just minted).
4
6
  *
5
7
  * Same seam and admission as `otto_submit_under_delegation`: they register only with a rig, the caller presents
6
8
  * Otto's server secret in the `x-otto-delegation-auth` request header (never in arguments), the registered
@@ -18,7 +20,9 @@ import { DELEGATED_TOOL_TRANSPORT_SCHEMA } from './execution-delegated-definitio
18
20
  export declare const DELEGATION_FENCE_TOOL_NAME: "otto_delegation_fence";
19
21
  export declare const DELEGATION_STATUS_TOOL_NAME: "otto_delegation_status";
20
22
  export declare const DELEGATION_REVOKE_TOOL_NAME: "otto_delegation_revoke";
21
- export declare const DELEGATION_ADMIN_TOOL_NAMES: readonly ["otto_delegation_fence", "otto_delegation_status", "otto_delegation_revoke"];
23
+ /** Records the per-swap cap the person chose, against the grant they just minted. */
24
+ export declare const DELEGATION_CAP_TOOL_NAME: "otto_delegation_cap";
25
+ export declare const DELEGATION_ADMIN_TOOL_NAMES: readonly ["otto_delegation_fence", "otto_delegation_status", "otto_delegation_revoke", "otto_delegation_cap"];
22
26
  /** The one PUBLIC delegation tool: the fence's public promise (present / name / digest / cap) — never user or grant data. */
23
27
  export declare const DELEGATION_FENCE_STATUS_TOOL_NAME: "otto_delegation_fence_status";
24
28
  export declare const DELEGATION_FENCE_INPUT_SCHEMA: z.ZodObject<{}, z.core.$strict>;
@@ -49,9 +53,74 @@ export declare const DELEGATION_STATUS_RESULT_SCHEMA: z.ZodObject<{
49
53
  delegation: z.ZodObject<{
50
54
  active: z.ZodBoolean;
51
55
  expires_at: z.ZodOptional<z.ZodString>;
56
+ per_swap_cap_usd: z.ZodOptional<z.ZodNumber>;
52
57
  }, z.core.$strict>;
53
58
  revocation_requested_here: z.ZodBoolean;
59
+ ruleset_version: z.ZodNumber;
60
+ mint_enabled: z.ZodBoolean;
54
61
  }, z.core.$strict>;
62
+ /**
63
+ * 🔴 TWO PHASES, BECAUSE THE RECORD NOW COMES BEFORE THE GRANT.
64
+ *
65
+ * Rounds 1 and 2 recorded a cap against a grant that already existed, and the codex gate broke both the
66
+ * same way: an expiry is the only thing a send can learn about a live grant, so two grants that share one
67
+ * are indistinguishable at enforcement however the row is keyed. Round 3 removes the collision instead of
68
+ * describing it.
69
+ *
70
+ * `reserve` — the SERVER picks a whole-second instant at or BEFORE the person's chosen duration that no
71
+ * durable row for this user occupies, writes the cap against it, and answers with the instant. The
72
+ * caller then mints with `mint_expires_at`, which is that instant plus a one-millisecond filler CDP
73
+ * truncates away (a bare `.000Z` is refused upstream — see `mintExpiryFor`).
74
+ * `confirm` — after the mint, the server re-reads the grant from CDP and refuses unless the instant CDP
75
+ * reports IS the reserved one. On a mismatch the fresh grant is REVOKED: a permission whose expiry
76
+ * does not match the row it was reserved against is one nothing may act under.
77
+ *
78
+ * The user is still never named by the caller — both phases resolve the identity from the access token.
79
+ */
80
+ export declare const DELEGATION_CAP_RESERVE_INPUT_SCHEMA: z.ZodObject<{
81
+ phase: z.ZodLiteral<"reserve">;
82
+ accessToken: z.ZodString;
83
+ perSwapCapUsd: z.ZodNumber;
84
+ requestedDays: z.ZodNumber;
85
+ mintKey: z.ZodString;
86
+ }, z.core.$strict>;
87
+ export declare const DELEGATION_CAP_CONFIRM_INPUT_SCHEMA: z.ZodObject<{
88
+ phase: z.ZodLiteral<"confirm">;
89
+ accessToken: z.ZodString;
90
+ mintKey: z.ZodString;
91
+ }, z.core.$strict>;
92
+ export declare const DELEGATION_CAP_INPUT_SCHEMA: z.ZodDiscriminatedUnion<[z.ZodObject<{
93
+ phase: z.ZodLiteral<"reserve">;
94
+ accessToken: z.ZodString;
95
+ perSwapCapUsd: z.ZodNumber;
96
+ requestedDays: z.ZodNumber;
97
+ mintKey: z.ZodString;
98
+ }, z.core.$strict>, z.ZodObject<{
99
+ phase: z.ZodLiteral<"confirm">;
100
+ accessToken: z.ZodString;
101
+ mintKey: z.ZodString;
102
+ }, z.core.$strict>], "phase">;
103
+ export declare const DELEGATION_CAP_RESULT_SCHEMA: z.ZodObject<{
104
+ phase: z.ZodEnum<{
105
+ reserve: "reserve";
106
+ confirm: "confirm";
107
+ }>;
108
+ user_id: z.ZodString;
109
+ expires_at: z.ZodString;
110
+ mint_expires_at: z.ZodOptional<z.ZodString>;
111
+ per_swap_cap_usd: z.ZodNumber;
112
+ state: z.ZodEnum<{
113
+ legacy: "legacy";
114
+ reserved: "reserved";
115
+ confirmed_active: "confirmed_active";
116
+ superseded: "superseded";
117
+ revoked: "revoked";
118
+ expired: "expired";
119
+ }>;
120
+ ruleset_version: z.ZodNumber;
121
+ recorded: z.ZodBoolean;
122
+ }, z.core.$strict>;
123
+ export type DelegationCapResult = z.infer<typeof DELEGATION_CAP_RESULT_SCHEMA>;
55
124
  export declare const DELEGATION_REVOKE_INPUT_SCHEMA: z.ZodUnion<readonly [z.ZodObject<{
56
125
  accessToken: z.ZodString;
57
126
  }, z.core.$strict>, z.ZodObject<{
@@ -73,6 +142,9 @@ export declare const DELEGATION_FENCE_STATUS_RESULT_SCHEMA: z.ZodObject<{
73
142
  present: z.ZodBoolean;
74
143
  policy_name: z.ZodString;
75
144
  per_swap_cap_usd: z.ZodLiteral<5000>;
145
+ per_swap_cap_min_usd: z.ZodLiteral<1>;
146
+ ruleset_version: z.ZodNumber;
147
+ mint_enabled: z.ZodBoolean;
76
148
  project_id: z.ZodOptional<z.ZodString>;
77
149
  rules_digest: z.ZodOptional<z.ZodString>;
78
150
  reason: z.ZodOptional<z.ZodEnum<{
@@ -86,12 +158,15 @@ export type DelegationFenceStatusResult = z.infer<typeof DELEGATION_FENCE_STATUS
86
158
  export declare const DELEGATION_FENCE_STATUS_TOOL_DEFINITION: Readonly<{
87
159
  name: "otto_delegation_fence_status";
88
160
  title: "Read the Model-B delegation fence (public promise: present, name, rules digest, per-swap cap)";
89
- description: "PUBLIC and read-only, no header: whether the Model-B project policy that fences every delegated send is installed and v-current on this server, with its versioned name, rules digest, the per-swap cap in USD, and Otto's PUBLIC CDP project id (a UUID — the authority an agent binds its mint to). Exposes ONLY the fence's public promise — never an end user, a grant, an address or a policy's contents. An agent about to mint a delegation (otto-execute delegate) reads this first, mints to the published project_id and no other, and refuses to mint when the fence is not present; the server enforces fence-before-authority on every delegated send regardless. Arguments: {}.";
161
+ description: "PUBLIC and read-only, no header: whether the Model-B project policy that fences every delegated send is installed and v-current on this server, with its versioned name, rules digest, the per-swap cap ceiling in USD (shared by every delegated user — a person may choose any whole-dollar cap from per_swap_cap_min_usd up to it, enforced server-side and recorded against their own grant), and Otto's PUBLIC CDP project id (a UUID — the authority an agent binds its mint to). Exposes ONLY the fence's public promise — never an end user, a grant, an address or a policy's contents. An agent about to mint a delegation (otto-execute delegate) reads this first, mints to the published project_id and no other, and refuses to mint when the fence is not present; the server enforces fence-before-authority on every delegated send regardless. Arguments: {}.";
90
162
  inputSchema: z.ZodObject<{}, z.core.$strict>;
91
163
  outputSchema: z.ZodObject<{
92
164
  present: z.ZodBoolean;
93
165
  policy_name: z.ZodString;
94
166
  per_swap_cap_usd: z.ZodLiteral<5000>;
167
+ per_swap_cap_min_usd: z.ZodLiteral<1>;
168
+ ruleset_version: z.ZodNumber;
169
+ mint_enabled: z.ZodBoolean;
95
170
  project_id: z.ZodOptional<z.ZodString>;
96
171
  rules_digest: z.ZodOptional<z.ZodString>;
97
172
  reason: z.ZodOptional<z.ZodEnum<{
@@ -152,7 +227,7 @@ export declare const DELEGATION_FENCE_TOOL_DEFINITION: Readonly<{
152
227
  export declare const DELEGATION_STATUS_TOOL_DEFINITION: Readonly<{
153
228
  name: "otto_delegation_status";
154
229
  title: "Read one end user's delegation status (token-bound)";
155
- description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry). Arguments: { accessToken } \u2014 the server resolves the user from the token; a client-sent user id is refused. Output is bound to that user; nothing about any other user is returned. ${string}`;
230
+ description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry and the per-swap cap recorded for it). Arguments: { accessToken } \u2014 the server resolves the user from the token; a client-sent user id is refused. delegation.per_swap_cap_usd is the number THIS user chose at mint time; it is ABSENT when no cap is recorded for the grant, which means the delegated send will refuse it \u2014 say so rather than showing the shared ceiling. fence.per_swap_cap_usd is that shared ceiling and is never a per-user number. Output is bound to that user; nothing about any other user is returned. ${string}`;
156
231
  inputSchema: z.ZodObject<{}, z.core.$loose>;
157
232
  strictInputSchema: z.ZodObject<{
158
233
  accessToken: z.ZodString;
@@ -169,8 +244,11 @@ export declare const DELEGATION_STATUS_TOOL_DEFINITION: Readonly<{
169
244
  delegation: z.ZodObject<{
170
245
  active: z.ZodBoolean;
171
246
  expires_at: z.ZodOptional<z.ZodString>;
247
+ per_swap_cap_usd: z.ZodOptional<z.ZodNumber>;
172
248
  }, z.core.$strict>;
173
249
  revocation_requested_here: z.ZodBoolean;
250
+ ruleset_version: z.ZodNumber;
251
+ mint_enabled: z.ZodBoolean;
174
252
  }, z.core.$strict>;
175
253
  annotations: Readonly<{
176
254
  readOnlyHint: true;
@@ -206,3 +284,46 @@ export declare const DELEGATION_REVOKE_TOOL_DEFINITION: Readonly<{
206
284
  openWorldHint: true;
207
285
  }>;
208
286
  }>;
287
+ export declare const DELEGATION_CAP_TOOL_DEFINITION: Readonly<{
288
+ name: "otto_delegation_cap";
289
+ title: "Reserve the expiry a delegation is minted with, record the chosen per-swap cap against it, then confirm the mint";
290
+ description: `TWO PHASES, both header authed, both resolving the end user from the access token. { phase: "reserve", accessToken, perSwapCapUsd, requestedDays, mintKey } picks a whole-second expiry instant at or BEFORE the requested duration that no durable row for this user already occupies, writes the chosen cap (whole USD, 1\u20265000) against it, and answers { expires_at, mint_expires_at, per_swap_cap_usd, recorded }. Call createDelegation with mint_expires_at EXACTLY as given \u2014 it is the reserved instant plus a one-millisecond filler, because CDP refuses an expiry ending .000 and truncates the filler away \u2014 and with mintKey as the idempotencyKey. Then { phase: "confirm", accessToken, mintKey } re-reads the grant from CDP and refuses (DELEGATION_CAP_GRANT_CHANGED) unless the instant CDP reports IS the reserved one, revoking the fresh grant when it is not. Why this shape: Coinbase issues no grant id and a send can learn nothing about a live grant except its expiry, so the expiry is made an identity BY CONSTRUCTION \u2014 reserved server-side, recorded before the mint, asserted after it. Until a reservation exists, otto_submit_under_delegation refuses that delegation (DELEGATION_CAP_UNRECORDED) rather than falling back to the 5000 USD ceiling. A reservation is IMMUTABLE per mint key \u2014 pressing again returns the same instant and the cap already in force, so raising a cap means minting a new permission (which the user is told replaces the old one). Coinbase's engine cannot hold this number: end-user accounts are fenced by ONE project-scope policy shared by every delegated user, so a lower per-user cap is enforced by Otto's server alone. ${string}`;
291
+ inputSchema: z.ZodObject<{}, z.core.$loose>;
292
+ strictInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
293
+ phase: z.ZodLiteral<"reserve">;
294
+ accessToken: z.ZodString;
295
+ perSwapCapUsd: z.ZodNumber;
296
+ requestedDays: z.ZodNumber;
297
+ mintKey: z.ZodString;
298
+ }, z.core.$strict>, z.ZodObject<{
299
+ phase: z.ZodLiteral<"confirm">;
300
+ accessToken: z.ZodString;
301
+ mintKey: z.ZodString;
302
+ }, z.core.$strict>], "phase">;
303
+ outputSchema: z.ZodObject<{
304
+ phase: z.ZodEnum<{
305
+ reserve: "reserve";
306
+ confirm: "confirm";
307
+ }>;
308
+ user_id: z.ZodString;
309
+ expires_at: z.ZodString;
310
+ mint_expires_at: z.ZodOptional<z.ZodString>;
311
+ per_swap_cap_usd: z.ZodNumber;
312
+ state: z.ZodEnum<{
313
+ legacy: "legacy";
314
+ reserved: "reserved";
315
+ confirmed_active: "confirmed_active";
316
+ superseded: "superseded";
317
+ revoked: "revoked";
318
+ expired: "expired";
319
+ }>;
320
+ ruleset_version: z.ZodNumber;
321
+ recorded: z.ZodBoolean;
322
+ }, z.core.$strict>;
323
+ annotations: Readonly<{
324
+ readOnlyHint: false;
325
+ destructiveHint: false;
326
+ idempotentHint: true;
327
+ openWorldHint: true;
328
+ }>;
329
+ }>;
@@ -1,6 +1,8 @@
1
1
  /**
2
- * execution-delegation-admin-definition.ts — the three header-authed delegation ADMIN tools (PR-1b, seat ruling
3
- * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`.
2
+ * execution-delegation-admin-definition.ts — the four header-authed delegation ADMIN tools (PR-1b, seat ruling
3
+ * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`, and
4
+ * `otto_delegation_cap` (Founder word `delegate cap choice`, 2026-09-02 — the per-swap cap a person chose,
5
+ * recorded against the grant they just minted).
4
6
  *
5
7
  * Same seam and admission as `otto_submit_under_delegation`: they register only with a rig, the caller presents
6
8
  * Otto's server secret in the `x-otto-delegation-auth` request header (never in arguments), the registered
@@ -14,16 +16,26 @@
14
16
  * proxy exposes only the token variant (asserted in PR-2).
15
17
  */
16
18
  import { z } from 'zod';
17
- import { MODEL_B_PER_SWAP_CAP_USD } from './execution-delegation-policy.js';
19
+ import { MODEL_B_DELEGATION_EXPIRY_MAX_DAYS, MODEL_B_DELEGATION_EXPIRY_MIN_DAYS, MODEL_B_PER_SWAP_CAP_MIN_USD, MODEL_B_PER_SWAP_CAP_USD, } from './execution-delegation-policy.js';
18
20
  import { DELEGATION_AUTH_HEADER, DELEGATED_TOOL_TRANSPORT_SCHEMA, } from './execution-delegated-definition.js';
21
+ import { CAP_RECORD_STATES, MINT_KEY_PATTERN } from './execution-delegation-cap-store.js';
19
22
  export const DELEGATION_FENCE_TOOL_NAME = 'otto_delegation_fence';
20
23
  export const DELEGATION_STATUS_TOOL_NAME = 'otto_delegation_status';
21
24
  export const DELEGATION_REVOKE_TOOL_NAME = 'otto_delegation_revoke';
25
+ /** Records the per-swap cap the person chose, against the grant they just minted. */
26
+ export const DELEGATION_CAP_TOOL_NAME = 'otto_delegation_cap';
22
27
  export const DELEGATION_ADMIN_TOOL_NAMES = Object.freeze([
23
28
  DELEGATION_FENCE_TOOL_NAME,
24
29
  DELEGATION_STATUS_TOOL_NAME,
25
30
  DELEGATION_REVOKE_TOOL_NAME,
31
+ DELEGATION_CAP_TOOL_NAME,
26
32
  ]);
33
+ /** A chosen per-swap cap, as every schema on this surface bounds it: whole USD, 1 … the engine ceiling. */
34
+ const PER_SWAP_CAP_SCHEMA = z
35
+ .number()
36
+ .int()
37
+ .min(MODEL_B_PER_SWAP_CAP_MIN_USD)
38
+ .max(MODEL_B_PER_SWAP_CAP_USD);
27
39
  /** The one PUBLIC delegation tool: the fence's public promise (present / name / digest / cap) — never user or grant data. */
28
40
  export const DELEGATION_FENCE_STATUS_TOOL_NAME = 'otto_delegation_fence_status';
29
41
  const END_USER_ID_PATTERN = /^[a-zA-Z0-9-]{1,100}$/;
@@ -67,9 +79,117 @@ export const DELEGATION_STATUS_RESULT_SCHEMA = z
67
79
  /** Active = reads back from CDP, not expired, and no revocation was requested on this server. */
68
80
  active: z.boolean(),
69
81
  expires_at: z.string().optional(),
82
+ /**
83
+ * The per-swap cap recorded for THIS grant — the number the person chose when they minted.
84
+ * ABSENT when none is recorded, and that absence is load-bearing: a delegated send for a grant
85
+ * with no recorded cap refuses, so the surface reading this must say the permission is not usable
86
+ * rather than quietly showing the ceiling.
87
+ */
88
+ per_swap_cap_usd: PER_SWAP_CAP_SCHEMA.optional(),
70
89
  })
71
90
  .strict(),
72
91
  revocation_requested_here: z.boolean(),
92
+ /**
93
+ * The cap-ruleset version THIS worker implements. The page and the agent CLI refuse to reserve or
94
+ * mint against a server reporting less than the version they were built for — a rolling deploy runs
95
+ * two binaries at once and the Coinbase fence is identical on both, so the fence cannot tell them
96
+ * apart and this is what does.
97
+ */
98
+ ruleset_version: z.number().int().min(1),
99
+ /**
100
+ * Whether a NEW permission can be created on this worker at all (the staged-deploy gate). It never
101
+ * gates this read and never gates revoke: pausing the creation of authority must not pause its
102
+ * withdrawal, and a permission that already stands keeps working under its own cap.
103
+ */
104
+ mint_enabled: z.boolean(),
105
+ })
106
+ .strict();
107
+ /* ── cap (round 3: RESERVE an expiry and record the cap against it, then CONFIRM the mint) ── */
108
+ /**
109
+ * 🔴 TWO PHASES, BECAUSE THE RECORD NOW COMES BEFORE THE GRANT.
110
+ *
111
+ * Rounds 1 and 2 recorded a cap against a grant that already existed, and the codex gate broke both the
112
+ * same way: an expiry is the only thing a send can learn about a live grant, so two grants that share one
113
+ * are indistinguishable at enforcement however the row is keyed. Round 3 removes the collision instead of
114
+ * describing it.
115
+ *
116
+ * `reserve` — the SERVER picks a whole-second instant at or BEFORE the person's chosen duration that no
117
+ * durable row for this user occupies, writes the cap against it, and answers with the instant. The
118
+ * caller then mints with `mint_expires_at`, which is that instant plus a one-millisecond filler CDP
119
+ * truncates away (a bare `.000Z` is refused upstream — see `mintExpiryFor`).
120
+ * `confirm` — after the mint, the server re-reads the grant from CDP and refuses unless the instant CDP
121
+ * reports IS the reserved one. On a mismatch the fresh grant is REVOKED: a permission whose expiry
122
+ * does not match the row it was reserved against is one nothing may act under.
123
+ *
124
+ * The user is still never named by the caller — both phases resolve the identity from the access token.
125
+ */
126
+ export const DELEGATION_CAP_RESERVE_INPUT_SCHEMA = z
127
+ .object({
128
+ phase: z.literal('reserve'),
129
+ accessToken: ACCESS_TOKEN_SCHEMA,
130
+ perSwapCapUsd: PER_SWAP_CAP_SCHEMA,
131
+ /**
132
+ * How long the person asked for. The server turns it into an instant itself — a caller-supplied expiry
133
+ * would put the choice of the enforcement key back in the browser, and it is the server choosing it
134
+ * that makes the key unique.
135
+ */
136
+ requestedDays: z
137
+ .number()
138
+ .int()
139
+ .min(MODEL_B_DELEGATION_EXPIRY_MIN_DAYS)
140
+ .max(MODEL_B_DELEGATION_EXPIRY_MAX_DAYS),
141
+ /**
142
+ * The `idempotencyKey` the caller WILL pass to `createDelegation`. It makes the reservation itself
143
+ * retry-safe: pressing again after a lost response returns the same instant rather than consuming a
144
+ * second one. It is NOT the enforcement key — `(userId, expiry)` is.
145
+ */
146
+ mintKey: z.string().regex(MINT_KEY_PATTERN, 'must be the mint idempotency key'),
147
+ })
148
+ .strict();
149
+ export const DELEGATION_CAP_CONFIRM_INPUT_SCHEMA = z
150
+ .object({
151
+ phase: z.literal('confirm'),
152
+ accessToken: ACCESS_TOKEN_SCHEMA,
153
+ /** Which reservation this mint was for. The reserved instant is read from the store, never from the caller. */
154
+ mintKey: z.string().regex(MINT_KEY_PATTERN, 'must be the mint idempotency key'),
155
+ })
156
+ .strict();
157
+ export const DELEGATION_CAP_INPUT_SCHEMA = z.discriminatedUnion('phase', [
158
+ DELEGATION_CAP_RESERVE_INPUT_SCHEMA,
159
+ DELEGATION_CAP_CONFIRM_INPUT_SCHEMA,
160
+ ]);
161
+ export const DELEGATION_CAP_RESULT_SCHEMA = z
162
+ .object({
163
+ phase: z.enum(['reserve', 'confirm']),
164
+ user_id: z.string().regex(END_USER_ID_PATTERN),
165
+ /**
166
+ * The RESERVED whole-second instant — the enforcement key. On `confirm` it is also what CDP reports for
167
+ * the live grant, because the call refuses otherwise.
168
+ */
169
+ expires_at: z.string(),
170
+ /**
171
+ * What to hand `createDelegation`: the reserved instant plus the one-millisecond filler. Present on
172
+ * `reserve` only — by `confirm` the mint has already happened.
173
+ */
174
+ mint_expires_at: z.string().optional(),
175
+ /**
176
+ * The cap IN FORCE at that instant, read back from the binding index — not necessarily the number the
177
+ * caller asked for.
178
+ */
179
+ per_swap_cap_usd: PER_SWAP_CAP_SCHEMA,
180
+ /**
181
+ * Where this permission is in its lifecycle. `reserved` authorises NOTHING — only `confirmed_active`
182
+ * does, and only while it is the one the send gate reads back.
183
+ */
184
+ state: z.enum(CAP_RECORD_STATES),
185
+ /** The cap ruleset this record requires; a worker that implements an older one refuses it. */
186
+ ruleset_version: z.number().int().min(1),
187
+ /**
188
+ * True when THIS call wrote the transition. False when it had already happened for this mint key:
189
+ * a reservation is immutable and a confirmation is one-shot, so the fields above are what already
190
+ * stands, and a caller wanting a different number mints a new permission.
191
+ */
192
+ recorded: z.boolean(),
73
193
  })
74
194
  .strict();
75
195
  /* ── revoke ── */
@@ -97,7 +217,21 @@ export const DELEGATION_FENCE_STATUS_RESULT_SCHEMA = z
97
217
  .object({
98
218
  present: z.boolean(),
99
219
  policy_name: z.string(),
220
+ /**
221
+ * The ENGINE's ceiling, shared by every delegated user — never one person's cap. A public tool has no
222
+ * user, so it can only ever publish this number and the floor below it.
223
+ */
100
224
  per_swap_cap_usd: z.literal(MODEL_B_PER_SWAP_CAP_USD),
225
+ /** The floor of the range a person may choose at mint time; their choice is enforced server-side. */
226
+ per_swap_cap_min_usd: z.literal(MODEL_B_PER_SWAP_CAP_MIN_USD),
227
+ /** The cap-ruleset version this worker implements; a client built for a newer one refuses to mint. */
228
+ ruleset_version: z.number().int().min(1),
229
+ /**
230
+ * Whether this worker will create a NEW permission at all. Published so the page and the CLI can say
231
+ * so before a person signs in, rather than discovering it at the reserve. Permissions that already
232
+ * stand keep working, and revoke always works.
233
+ */
234
+ mint_enabled: z.boolean(),
101
235
  /** Otto's PUBLIC CDP project id (a UUID): the authority the agent CLI binds its mint to. */
102
236
  project_id: z
103
237
  .string()
@@ -114,7 +248,7 @@ export const DELEGATION_FENCE_STATUS_RESULT_SCHEMA = z
114
248
  export const DELEGATION_FENCE_STATUS_TOOL_DEFINITION = Object.freeze({
115
249
  name: DELEGATION_FENCE_STATUS_TOOL_NAME,
116
250
  title: 'Read the Model-B delegation fence (public promise: present, name, rules digest, per-swap cap)',
117
- description: `PUBLIC and read-only, no header: whether the Model-B project policy that fences every delegated send is installed and v-current on this server, with its versioned name, rules digest, the per-swap cap in USD, and Otto's PUBLIC CDP project id (a UUID — the authority an agent binds its mint to). Exposes ONLY the fence's public promise — never an end user, a grant, an address or a policy's contents. An agent about to mint a delegation (otto-execute delegate) reads this first, mints to the published project_id and no other, and refuses to mint when the fence is not present; the server enforces fence-before-authority on every delegated send regardless. Arguments: {}.`,
251
+ description: `PUBLIC and read-only, no header: whether the Model-B project policy that fences every delegated send is installed and v-current on this server, with its versioned name, rules digest, the per-swap cap ceiling in USD (shared by every delegated user \u2014 a person may choose any whole-dollar cap from per_swap_cap_min_usd up to it, enforced server-side and recorded against their own grant), and Otto's PUBLIC CDP project id (a UUID — the authority an agent binds its mint to). Exposes ONLY the fence's public promise — never an end user, a grant, an address or a policy's contents. An agent about to mint a delegation (otto-execute delegate) reads this first, mints to the published project_id and no other, and refuses to mint when the fence is not present; the server enforces fence-before-authority on every delegated send regardless. Arguments: {}.`,
118
252
  inputSchema: DELEGATION_FENCE_STATUS_INPUT_SCHEMA,
119
253
  outputSchema: DELEGATION_FENCE_STATUS_RESULT_SCHEMA,
120
254
  annotations: Object.freeze({
@@ -142,7 +276,7 @@ export const DELEGATION_FENCE_TOOL_DEFINITION = Object.freeze({
142
276
  export const DELEGATION_STATUS_TOOL_DEFINITION = Object.freeze({
143
277
  name: DELEGATION_STATUS_TOOL_NAME,
144
278
  title: "Read one end user's delegation status (token-bound)",
145
- description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry). Arguments: { accessToken } — the server resolves the user from the token; a client-sent user id is refused. Output is bound to that user; nothing about any other user is returned. ${AUTH_SENTENCE}`,
279
+ description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry and the per-swap cap recorded for it). Arguments: { accessToken } — the server resolves the user from the token; a client-sent user id is refused. delegation.per_swap_cap_usd is the number THIS user chose at mint time; it is ABSENT when no cap is recorded for the grant, which means the delegated send will refuse it — say so rather than showing the shared ceiling. fence.per_swap_cap_usd is that shared ceiling and is never a per-user number. Output is bound to that user; nothing about any other user is returned. ${AUTH_SENTENCE}`,
146
280
  inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
147
281
  strictInputSchema: DELEGATION_STATUS_INPUT_SCHEMA,
148
282
  outputSchema: DELEGATION_STATUS_RESULT_SCHEMA,
@@ -167,4 +301,19 @@ export const DELEGATION_REVOKE_TOOL_DEFINITION = Object.freeze({
167
301
  openWorldHint: true,
168
302
  }),
169
303
  });
304
+ export const DELEGATION_CAP_TOOL_DEFINITION = Object.freeze({
305
+ name: DELEGATION_CAP_TOOL_NAME,
306
+ title: "Reserve the expiry a delegation is minted with, record the chosen per-swap cap against it, then confirm the mint",
307
+ description: `TWO PHASES, both header authed, both resolving the end user from the access token. { phase: "reserve", accessToken, perSwapCapUsd, requestedDays, mintKey } picks a whole-second expiry instant at or BEFORE the requested duration that no durable row for this user already occupies, writes the chosen cap (whole USD, ${MODEL_B_PER_SWAP_CAP_MIN_USD}…${MODEL_B_PER_SWAP_CAP_USD}) against it, and answers { expires_at, mint_expires_at, per_swap_cap_usd, recorded }. Call createDelegation with mint_expires_at EXACTLY as given — it is the reserved instant plus a one-millisecond filler, because CDP refuses an expiry ending .000 and truncates the filler away — and with mintKey as the idempotencyKey. Then { phase: "confirm", accessToken, mintKey } re-reads the grant from CDP and refuses (DELEGATION_CAP_GRANT_CHANGED) unless the instant CDP reports IS the reserved one, revoking the fresh grant when it is not. Why this shape: Coinbase issues no grant id and a send can learn nothing about a live grant except its expiry, so the expiry is made an identity BY CONSTRUCTION — reserved server-side, recorded before the mint, asserted after it. Until a reservation exists, otto_submit_under_delegation refuses that delegation (DELEGATION_CAP_UNRECORDED) rather than falling back to the ${MODEL_B_PER_SWAP_CAP_USD} USD ceiling. A reservation is IMMUTABLE per mint key — pressing again returns the same instant and the cap already in force, so raising a cap means minting a new permission (which the user is told replaces the old one). Coinbase's engine cannot hold this number: end-user accounts are fenced by ONE project-scope policy shared by every delegated user, so a lower per-user cap is enforced by Otto's server alone. ${AUTH_SENTENCE}`,
308
+ inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
309
+ strictInputSchema: DELEGATION_CAP_INPUT_SCHEMA,
310
+ outputSchema: DELEGATION_CAP_RESULT_SCHEMA,
311
+ annotations: Object.freeze({
312
+ readOnlyHint: false,
313
+ destructiveHint: false,
314
+ // Idempotent by construction: the record is immutable, so a repeat returns what is already there.
315
+ idempotentHint: true,
316
+ openWorldHint: true,
317
+ }),
318
+ });
170
319
  //# sourceMappingURL=execution-delegation-admin-definition.js.map