@crediolabs/policy-synth 0.1.3 → 0.1.5

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 (194) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +193 -5
  3. package/dist/adapters/interpreter/adapter.d.ts +38 -0
  4. package/dist/adapters/interpreter/adapter.js +522 -0
  5. package/dist/adapters/interpreter/index.d.ts +1 -0
  6. package/dist/adapters/interpreter/index.js +2 -0
  7. package/dist/adapters/oz/adapter.js +2 -0
  8. package/dist/codegen/compile-gate.d.ts +33 -0
  9. package/dist/codegen/compile-gate.js +119 -0
  10. package/dist/codegen/index.d.ts +2 -0
  11. package/dist/codegen/index.js +8 -0
  12. package/dist/codegen/template.d.ts +18 -0
  13. package/dist/codegen/template.js +131 -0
  14. package/dist/errors.d.ts +1 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +2 -0
  17. package/dist/ir/types.d.ts +13 -2
  18. package/dist/predicate/encode.d.ts +10 -0
  19. package/dist/predicate/encode.js +249 -0
  20. package/dist/predicate/index.d.ts +1 -0
  21. package/dist/predicate/index.js +2 -0
  22. package/dist/record/decode.d.ts +6 -3
  23. package/dist/record/decode.js +13 -3
  24. package/dist/review-card/builder.d.ts +14 -0
  25. package/dist/review-card/builder.js +261 -0
  26. package/dist/review-card/conflict.d.ts +40 -0
  27. package/dist/review-card/conflict.js +111 -0
  28. package/dist/review-card/cross-check.d.ts +11 -0
  29. package/dist/review-card/cross-check.js +148 -0
  30. package/dist/review-card/index.d.ts +3 -0
  31. package/dist/review-card/index.js +4 -0
  32. package/dist/run/index.d.ts +31 -0
  33. package/dist/run/index.js +164 -0
  34. package/dist/run/schemas.d.ts +2003 -0
  35. package/dist/run/schemas.js +215 -0
  36. package/dist/synth/compose-from-recording.d.ts +35 -7
  37. package/dist/synth/compose-from-recording.js +225 -34
  38. package/dist/synth/deny-cases.d.ts +12 -0
  39. package/dist/synth/deny-cases.js +377 -0
  40. package/dist/synth/evaluate.d.ts +39 -0
  41. package/dist/synth/evaluate.js +425 -0
  42. package/dist/synth/harness.d.ts +16 -0
  43. package/dist/synth/harness.js +26 -0
  44. package/dist/synth/index.d.ts +4 -0
  45. package/dist/synth/index.js +4 -0
  46. package/dist/synth/minimize.d.ts +4 -0
  47. package/dist/synth/minimize.js +38 -0
  48. package/dist/synth/predicate-literals.d.ts +5 -0
  49. package/dist/synth/predicate-literals.js +25 -0
  50. package/dist/synth/synthesize-from-recording.d.ts +37 -5
  51. package/dist/synth/synthesize-from-recording.js +550 -18
  52. package/dist/types.d.ts +40 -1
  53. package/dist/types.js +17 -0
  54. package/dist/verify/envelope.d.ts +15 -0
  55. package/dist/verify/envelope.js +22 -0
  56. package/dist/verify/index.d.ts +3 -0
  57. package/dist/verify/index.js +3 -0
  58. package/dist/verify/simulate.d.ts +31 -0
  59. package/dist/verify/simulate.js +258 -0
  60. package/dist/verify/verify.d.ts +21 -0
  61. package/dist/verify/verify.js +189 -0
  62. package/dist-cjs/adapters/interpreter/adapter.d.ts +38 -0
  63. package/dist-cjs/adapters/interpreter/adapter.js +527 -0
  64. package/dist-cjs/adapters/interpreter/index.d.ts +1 -0
  65. package/dist-cjs/adapters/interpreter/index.js +8 -0
  66. package/dist-cjs/adapters/oz/adapter.d.ts +20 -0
  67. package/dist-cjs/adapters/oz/adapter.js +289 -0
  68. package/dist-cjs/adapters/oz/index.d.ts +1 -0
  69. package/dist-cjs/adapters/oz/index.js +8 -0
  70. package/dist-cjs/codegen/compile-gate.d.ts +33 -0
  71. package/dist-cjs/codegen/compile-gate.js +123 -0
  72. package/dist-cjs/codegen/index.d.ts +2 -0
  73. package/dist-cjs/codegen/index.js +14 -0
  74. package/dist-cjs/codegen/template.d.ts +18 -0
  75. package/dist-cjs/codegen/template.js +134 -0
  76. package/dist-cjs/errors.d.ts +37 -0
  77. package/dist-cjs/errors.js +3 -0
  78. package/dist-cjs/index.d.ts +11 -0
  79. package/dist-cjs/index.js +27 -0
  80. package/dist-cjs/ir/index.d.ts +1 -0
  81. package/dist-cjs/ir/index.js +3 -0
  82. package/dist-cjs/ir/types.d.ts +108 -0
  83. package/dist-cjs/ir/types.js +12 -0
  84. package/dist-cjs/mandate/index.d.ts +2 -0
  85. package/dist-cjs/mandate/index.js +6 -0
  86. package/dist-cjs/mandate/to-ir.d.ts +3 -0
  87. package/dist-cjs/mandate/to-ir.js +63 -0
  88. package/dist-cjs/mandate/types.d.ts +20 -0
  89. package/dist-cjs/mandate/types.js +9 -0
  90. package/dist-cjs/package.json +3 -0
  91. package/dist-cjs/predicate/encode.d.ts +10 -0
  92. package/dist-cjs/predicate/encode.js +252 -0
  93. package/dist-cjs/predicate/index.d.ts +1 -0
  94. package/dist-cjs/predicate/index.js +6 -0
  95. package/dist-cjs/record/decode.d.ts +79 -0
  96. package/dist-cjs/record/decode.js +398 -0
  97. package/dist-cjs/record/freshness.d.ts +17 -0
  98. package/dist-cjs/record/freshness.js +55 -0
  99. package/dist-cjs/record/index.d.ts +21 -0
  100. package/dist-cjs/record/index.js +166 -0
  101. package/dist-cjs/record/movements.d.ts +20 -0
  102. package/dist-cjs/record/movements.js +192 -0
  103. package/dist-cjs/record/rpc.d.ts +22 -0
  104. package/dist-cjs/record/rpc.js +74 -0
  105. package/dist-cjs/record/validate.d.ts +22 -0
  106. package/dist-cjs/record/validate.js +63 -0
  107. package/dist-cjs/registry/identify.d.ts +11 -0
  108. package/dist-cjs/registry/identify.js +87 -0
  109. package/dist-cjs/registry/index.d.ts +3 -0
  110. package/dist-cjs/registry/index.js +15 -0
  111. package/dist-cjs/registry/known-addresses.d.ts +16 -0
  112. package/dist-cjs/registry/known-addresses.js +53 -0
  113. package/dist-cjs/registry/protocols.d.ts +38 -0
  114. package/dist-cjs/registry/protocols.js +153 -0
  115. package/dist-cjs/review-card/builder.d.ts +14 -0
  116. package/dist-cjs/review-card/builder.js +264 -0
  117. package/dist-cjs/review-card/conflict.d.ts +40 -0
  118. package/dist-cjs/review-card/conflict.js +114 -0
  119. package/dist-cjs/review-card/cross-check.d.ts +11 -0
  120. package/dist-cjs/review-card/cross-check.js +151 -0
  121. package/dist-cjs/review-card/index.d.ts +3 -0
  122. package/dist-cjs/review-card/index.js +10 -0
  123. package/dist-cjs/run/index.d.ts +31 -0
  124. package/dist-cjs/run/index.js +178 -0
  125. package/dist-cjs/run/schemas.d.ts +2003 -0
  126. package/dist-cjs/run/schemas.js +218 -0
  127. package/dist-cjs/seams/index.d.ts +1 -0
  128. package/dist-cjs/seams/index.js +3 -0
  129. package/dist-cjs/seams/types.d.ts +66 -0
  130. package/dist-cjs/seams/types.js +12 -0
  131. package/dist-cjs/synth/compose-from-recording.d.ts +64 -0
  132. package/dist-cjs/synth/compose-from-recording.js +356 -0
  133. package/dist-cjs/synth/deny-cases.d.ts +12 -0
  134. package/dist-cjs/synth/deny-cases.js +380 -0
  135. package/dist-cjs/synth/evaluate.d.ts +39 -0
  136. package/dist-cjs/synth/evaluate.js +428 -0
  137. package/dist-cjs/synth/harness.d.ts +16 -0
  138. package/dist-cjs/synth/harness.js +29 -0
  139. package/dist-cjs/synth/index.d.ts +9 -0
  140. package/dist-cjs/synth/index.js +23 -0
  141. package/dist-cjs/synth/lower.d.ts +23 -0
  142. package/dist-cjs/synth/lower.js +119 -0
  143. package/dist-cjs/synth/minimize.d.ts +4 -0
  144. package/dist-cjs/synth/minimize.js +41 -0
  145. package/dist-cjs/synth/predicate-literals.d.ts +5 -0
  146. package/dist-cjs/synth/predicate-literals.js +28 -0
  147. package/dist-cjs/synth/scope.d.ts +26 -0
  148. package/dist-cjs/synth/scope.js +81 -0
  149. package/dist-cjs/synth/synthesize-from-mandate.d.ts +5 -0
  150. package/dist-cjs/synth/synthesize-from-mandate.js +37 -0
  151. package/dist-cjs/synth/synthesize-from-recording.d.ts +49 -0
  152. package/dist-cjs/synth/synthesize-from-recording.js +711 -0
  153. package/dist-cjs/types.d.ts +288 -0
  154. package/dist-cjs/types.js +55 -0
  155. package/dist-cjs/verify/envelope.d.ts +15 -0
  156. package/dist-cjs/verify/envelope.js +23 -0
  157. package/dist-cjs/verify/index.d.ts +3 -0
  158. package/dist-cjs/verify/index.js +8 -0
  159. package/dist-cjs/verify/simulate.d.ts +31 -0
  160. package/dist-cjs/verify/simulate.js +261 -0
  161. package/dist-cjs/verify/verify.d.ts +21 -0
  162. package/dist-cjs/verify/verify.js +192 -0
  163. package/package.json +43 -3
  164. package/src/adapters/interpreter/adapter.ts +642 -0
  165. package/src/adapters/interpreter/index.ts +8 -0
  166. package/src/adapters/oz/adapter.ts +2 -0
  167. package/src/codegen/compile-gate.ts +162 -0
  168. package/src/codegen/index.ts +17 -0
  169. package/src/codegen/template.ts +148 -0
  170. package/src/errors.ts +2 -0
  171. package/src/index.ts +2 -0
  172. package/src/ir/types.ts +9 -2
  173. package/src/predicate/encode.ts +307 -0
  174. package/src/predicate/index.ts +3 -0
  175. package/src/record/decode.ts +21 -10
  176. package/src/review-card/builder.ts +303 -0
  177. package/src/review-card/conflict.ts +143 -0
  178. package/src/review-card/cross-check.ts +158 -0
  179. package/src/review-card/index.ts +12 -0
  180. package/src/run/index.ts +213 -0
  181. package/src/run/schemas.ts +242 -0
  182. package/src/synth/compose-from-recording.ts +277 -43
  183. package/src/synth/deny-cases.ts +466 -0
  184. package/src/synth/evaluate.ts +493 -0
  185. package/src/synth/harness.ts +40 -0
  186. package/src/synth/index.ts +12 -0
  187. package/src/synth/minimize.ts +44 -0
  188. package/src/synth/predicate-literals.ts +27 -0
  189. package/src/synth/synthesize-from-recording.ts +655 -19
  190. package/src/types.ts +38 -2
  191. package/src/verify/envelope.ts +28 -0
  192. package/src/verify/index.ts +5 -0
  193. package/src/verify/simulate.ts +311 -0
  194. package/src/verify/verify.ts +243 -0
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ // packages/policy-synth/src/run/schemas.ts
3
+ //
4
+ // Zod schemas mirroring the policy-synth core domain types. These are the
5
+ // public input / output shapes exposed over MCP and the CLI. They are kept
6
+ // hand-written (rather than derived) because the MCP SDK needs a runtime
7
+ // Zod object at the transport boundary; a drift test asserts they stay in
8
+ // step with the TS source of truth.
9
+ //
10
+ // i128 amounts and other large integers are carried as base-10 decimal strings
11
+ // end-to-end (no JS number coercion). Networks are pinned to the same closed
12
+ // set the core defines. The discriminated union on `source` exposes BOTH
13
+ // synthesize_policy front-ends through a single tool input.
14
+ //
15
+ // This module is the SINGLE source of truth for these shapes. The MCP package
16
+ // imports them here so its tool-shape bindings stay in step; the CLI imports
17
+ // them here so it can build the same args envelope the MCP transport builds.
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.ToolErrorSchema = exports.SynthesizePolicyInputSchema = exports.SynthesizePolicyRecordingInputSchema = exports.InterpreterOptionsSchema = exports.SynthesizePolicyMandateInputSchema = exports.RecordTransactionInputSchema = exports.OzAdapterConfigSchema = exports.ComposeUserResponsesSchema = exports.MandateSpecSchema = exports.RecordedTransactionSchema = exports.ParseConfidenceSchema = exports.OnChainEventSchema = exports.TokenMovementSchema = exports.ContractInvocationSchema = exports.ScValSchema = exports.NetworkSchema = void 0;
20
+ const zod_1 = require("zod");
21
+ /** Soroban `valid_until` is a u32 ledger sequence; a value above this cannot be
22
+ * installed on-chain, so reject it at the boundary (fail-closed). */
23
+ const U32_MAX = 4294967295;
24
+ /** Upper bound on top-level invocations in a recorded transaction. A real
25
+ * Stellar tx caps operations well below this; the bound stops a hand-crafted
26
+ * payload from turning one request into an unbounded synthesis (DoS). */
27
+ const MAX_INVOCATIONS = 512;
28
+ exports.NetworkSchema = zod_1.z.enum(['mainnet', 'testnet']);
29
+ /** ScVal subset - normalised subset the synth consumes. Mirrors
30
+ * `ScVal` in packages/policy-synth/src/types.ts. */
31
+ exports.ScValSchema = zod_1.z.lazy(() => zod_1.z.union([
32
+ zod_1.z.object({ type: zod_1.z.literal('address'), value: zod_1.z.string() }),
33
+ // i128 is SIGNED: real events carry negatives (e.g. a fee-adjustment/refund),
34
+ // so the recorder's own output must round-trip through this schema. u64/u32
35
+ // are unsigned and stay non-negative.
36
+ zod_1.z.object({ type: zod_1.z.literal('i128'), value: zod_1.z.string().regex(/^-?[0-9]+$/) }),
37
+ zod_1.z.object({ type: zod_1.z.literal('u64'), value: zod_1.z.string().regex(/^[0-9]+$/) }),
38
+ zod_1.z.object({ type: zod_1.z.literal('u32'), value: zod_1.z.string().regex(/^[0-9]+$/) }),
39
+ zod_1.z.object({ type: zod_1.z.literal('symbol'), value: zod_1.z.string() }),
40
+ zod_1.z.object({ type: zod_1.z.literal('vec'), value: zod_1.z.array(exports.ScValSchema) }),
41
+ zod_1.z.object({ type: zod_1.z.literal('bytes'), value: zod_1.z.string() }),
42
+ zod_1.z.object({ type: zod_1.z.literal('other'), value: zod_1.z.string() }),
43
+ ]));
44
+ /** ContractInvocation mirrors the core. Annotated with an explicit
45
+ * `z.ZodType<unknown>` (like ScValSchema above) so the self-referential
46
+ * `subInvocations` field does not trip TS's circular type inference. */
47
+ exports.ContractInvocationSchema = zod_1.z.object({
48
+ contract: zod_1.z.string(),
49
+ fn: zod_1.z.string(),
50
+ args: zod_1.z.array(exports.ScValSchema),
51
+ subInvocations: zod_1.z.array(zod_1.z.lazy(() => exports.ContractInvocationSchema)),
52
+ });
53
+ exports.TokenMovementSchema = zod_1.z.object({
54
+ token: zod_1.z.string(),
55
+ from: zod_1.z.string(),
56
+ to: zod_1.z.string(),
57
+ // The recorder reads the amount straight from the signed i128 event value
58
+ // (record/movements.ts readAmount), so a non-standard token that emits a
59
+ // negative transfer/mint/burn amount round-trips as a negative string. Mirror
60
+ // that here; the synth gate, not the wire schema, decides what to do with it.
61
+ amount: zod_1.z.string().regex(/^-?[0-9]+$/),
62
+ });
63
+ exports.OnChainEventSchema = zod_1.z.object({
64
+ contract: zod_1.z.string(),
65
+ topics: zod_1.z.array(zod_1.z.string()),
66
+ data: exports.ScValSchema,
67
+ });
68
+ exports.ParseConfidenceSchema = zod_1.z.object({
69
+ overall: zod_1.z.number().min(0).max(1),
70
+ knownContracts: zod_1.z.array(zod_1.z.string()),
71
+ unknownContracts: zod_1.z.array(zod_1.z.object({
72
+ contract: zod_1.z.string(),
73
+ reason: zod_1.z.enum(['no-abi', 'version-mismatch', 'opaque-result']),
74
+ })),
75
+ opaqueScVals: zod_1.z.array(zod_1.z.object({ path: zod_1.z.string(), type: zod_1.z.string() })),
76
+ thresholdUsed: zod_1.z.number().min(0).max(1),
77
+ });
78
+ /** RecordedTransaction mirrors the core RecordedTransaction. The output shape
79
+ * is referenced by name in the tool result structured content; we deliberately
80
+ * type it loosely (`z.unknown()`) on the success path so the core remains the
81
+ * single source of truth for the wire payload. */
82
+ exports.RecordedTransactionSchema = zod_1.z
83
+ .object({
84
+ network: exports.NetworkSchema,
85
+ signers: zod_1.z.array(zod_1.z.string()),
86
+ invocations: zod_1.z.array(exports.ContractInvocationSchema).max(MAX_INVOCATIONS),
87
+ tokenMovements: zod_1.z.array(exports.TokenMovementSchema),
88
+ events: zod_1.z.array(exports.OnChainEventSchema),
89
+ authEntries: zod_1.z.array(zod_1.z.unknown()),
90
+ ledgerSequence: zod_1.z.number().int().nonnegative(),
91
+ fetchedAt: zod_1.z.number().int().nonnegative(),
92
+ parseConfidence: exports.ParseConfidenceSchema,
93
+ sourceAccount: zod_1.z.string(),
94
+ })
95
+ .passthrough();
96
+ /** MandateSpec mirrors the core MandateSpec. The deterministic Mandate
97
+ * front-end needs no parseConfidence; the tool adapter injects the full
98
+ * confidence after synthesis so the orchestrator can compare. */
99
+ exports.MandateSpecSchema = zod_1.z
100
+ .object({
101
+ chain: zod_1.z.literal('stellar'),
102
+ contract: zod_1.z.string(),
103
+ method: zod_1.z.string().optional(),
104
+ spendingLimit: zod_1.z
105
+ .object({
106
+ token: zod_1.z.string(),
107
+ limit: zod_1.z.string().regex(/^[0-9]+$/),
108
+ windowSeconds: zod_1.z.number().int().positive(),
109
+ })
110
+ .optional(),
111
+ // A threshold of 0 means "0 approvals", which is not a real M-of-N gate.
112
+ approvalThreshold: zod_1.z.number().int().positive().optional(),
113
+ recipients: zod_1.z.array(zod_1.z.string()).optional(),
114
+ expiry: zod_1.z
115
+ .object({
116
+ validUntilLedger: zod_1.z.number().int().positive().max(U32_MAX).optional(),
117
+ validUntilUnixSeconds: zod_1.z.number().int().positive().optional(),
118
+ })
119
+ .optional(),
120
+ })
121
+ .passthrough();
122
+ /** ComposeUserResponses mirrors the core. */
123
+ exports.ComposeUserResponsesSchema = zod_1.z
124
+ .object({
125
+ windowSeconds: zod_1.z.number().int().positive().optional(),
126
+ validUntilLedger: zod_1.z.number().int().positive().max(U32_MAX).optional(),
127
+ limitAmount: zod_1.z
128
+ .string()
129
+ .regex(/^[0-9]+$/)
130
+ .optional(),
131
+ invocationLimit: zod_1.z.number().int().positive().optional(),
132
+ })
133
+ .passthrough();
134
+ /** OzAdapterConfig - the per-network OZ built-in instance addresses. */
135
+ exports.OzAdapterConfigSchema = zod_1.z.object({
136
+ network: exports.NetworkSchema,
137
+ instances: zod_1.z.object({
138
+ spending_limit: zod_1.z.string(),
139
+ simple_threshold: zod_1.z.string(),
140
+ weighted_threshold: zod_1.z.string(),
141
+ }),
142
+ });
143
+ // ===== record_transaction =====
144
+ exports.RecordTransactionInputSchema = zod_1.z
145
+ .object({
146
+ hash: zod_1.z.string().min(1).optional(),
147
+ xdr: zod_1.z.string().min(1).optional(),
148
+ network: exports.NetworkSchema,
149
+ confidenceOverride: zod_1.z.number().min(0).max(1).optional(),
150
+ })
151
+ .refine((v) => !(v.hash && v.xdr), {
152
+ message: 'provide exactly one of `hash` or `xdr`, not both',
153
+ })
154
+ .refine((v) => Boolean(v.hash) || Boolean(v.xdr), {
155
+ message: 'one of `hash` or `xdr` is required',
156
+ });
157
+ // ===== synthesize_policy =====
158
+ //
159
+ // Discriminated union on `source` exposes BOTH front-ends through ONE tool.
160
+ // - `source: 'mandate'` -> calls synthesizeFromMandate
161
+ // - `source: 'recording'` -> calls synthesizeFromRecording
162
+ exports.SynthesizePolicyMandateInputSchema = zod_1.z.object({
163
+ source: zod_1.z.literal('mandate'),
164
+ mandate: exports.MandateSpecSchema,
165
+ ozConfig: exports.OzAdapterConfigSchema.optional(),
166
+ });
167
+ /** Interpreter opt-in for the recording path. Present -> constraints OZ cannot
168
+ * express (per-method scoping, invocation-count windows, oracle bounds, exact
169
+ * hop paths) lower to a real interpreter predicate document instead of being
170
+ * surfaced as warnings. The core deep-validates `smartAccountAddress` (a C...
171
+ * contract, not the recording's G... source) and the tighten-only oracle
172
+ * bounds; the schema stays light so the core owns the friendly ToolErrors. */
173
+ exports.InterpreterOptionsSchema = zod_1.z.object({
174
+ smartAccountAddress: zod_1.z.string(),
175
+ installNonce: zod_1.z.number().int().positive().optional(),
176
+ oracleParams: zod_1.z
177
+ .object({
178
+ maxStalenessSeconds: zod_1.z.number().int().positive().optional(),
179
+ maxDeviationBps: zod_1.z.number().int().positive().optional(),
180
+ })
181
+ .optional(),
182
+ });
183
+ exports.SynthesizePolicyRecordingInputSchema = zod_1.z.object({
184
+ source: zod_1.z.literal('recording'),
185
+ recordedTx: exports.RecordedTransactionSchema,
186
+ network: exports.NetworkSchema,
187
+ userResponses: exports.ComposeUserResponsesSchema.optional(),
188
+ confidenceOverride: zod_1.z.object({ threshold: zod_1.z.number().min(0).max(1) }).optional(),
189
+ interpreter: exports.InterpreterOptionsSchema.optional(),
190
+ ozConfig: exports.OzAdapterConfigSchema.optional(),
191
+ });
192
+ exports.SynthesizePolicyInputSchema = zod_1.z.discriminatedUnion('source', [
193
+ exports.SynthesizePolicyMandateInputSchema,
194
+ exports.SynthesizePolicyRecordingInputSchema,
195
+ ]);
196
+ // ===== Error envelope (canonical) =====
197
+ //
198
+ // Mirrors ToolError from packages/policy-synth/src/errors.ts. We use a
199
+ // `z.string()` for `code` (not an enum) because the core's ErrorCode union
200
+ // evolves over time; the transport contract only promises a string code the
201
+ // caller can dispatch on. A drift test asserts the canonical codes still
202
+ // pass through unchanged.
203
+ exports.ToolErrorSchema = zod_1.z
204
+ .object({
205
+ code: zod_1.z.string(),
206
+ message: zod_1.z.string(),
207
+ severity: zod_1.z.enum(['info', 'warning', 'error', 'fatal']),
208
+ retryable: zod_1.z.boolean(),
209
+ remediation: zod_1.z
210
+ .object({
211
+ toolCall: zod_1.z.object({ name: zod_1.z.string(), args: zod_1.z.record(zod_1.z.unknown()) }).optional(),
212
+ userQuestion: zod_1.z.object({ code: zod_1.z.string(), question: zod_1.z.string() }).optional(),
213
+ docsUrl: zod_1.z.string().optional(),
214
+ })
215
+ .optional(),
216
+ details: zod_1.z.unknown().optional(),
217
+ })
218
+ .passthrough();
@@ -0,0 +1 @@
1
+ export type { ChainDecoder, CompileResult, CustodyAdapter, CustodyCapabilities, CustodyMode, PolicySource, SimulationResult, } from './types.ts';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // src/seams/index.ts - re-export the three custody-seam contracts.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,66 @@
1
+ import type { ToolResponse } from '../errors.ts';
2
+ import type { PolicyIR } from '../ir/types.ts';
3
+ import type { Network, ProposedPolicy, RecordedTransaction, ScVal } from '../types.ts';
4
+ /** INPUT: something that produces a normalized RecordedTransaction. */
5
+ export interface PolicySource {
6
+ readonly name: string;
7
+ capture(input: {
8
+ hash?: string;
9
+ xdr?: string;
10
+ network: Network;
11
+ }): Promise<ToolResponse<RecordedTransaction>>;
12
+ }
13
+ /** DECODE: chain-specific call data -> the normalized facts the synth reasons
14
+ * over. */
15
+ export interface ChainDecoder {
16
+ readonly chain: 'stellar' | 'evm';
17
+ decodeInvocation(tx: RecordedTransaction): {
18
+ contract: string;
19
+ method: string;
20
+ args: ScVal[];
21
+ };
22
+ }
23
+ /** OZ = enforce; `log_only` is reserved for shadow mode (out of scope). */
24
+ export type CustodyMode = 'enforce' | 'log_only';
25
+ /** What a backend can express. A construct needing a false flag is flagged
26
+ * `uncovered` by the adapter, never silently dropped. */
27
+ export interface CustodyCapabilities {
28
+ supportsOraclePrice: boolean;
29
+ supportsSpendWindow: boolean;
30
+ supportsInvocationCount: boolean;
31
+ supportsTimeExpiry: boolean;
32
+ supportsThreshold: boolean;
33
+ supportsGeneralPredicate: boolean;
34
+ }
35
+ /** The result of compiling a PolicyIR for one backend. */
36
+ export interface CompileResult {
37
+ /** false => some IR construct this backend cannot express (see `uncovered`). */
38
+ covered: boolean;
39
+ /** Human-readable list of unsupported constructs. */
40
+ uncovered: string[];
41
+ /** The backend-native installable policy, assembled when a rule lowered. */
42
+ proposed?: ProposedPolicy;
43
+ }
44
+ /** Result of a simulate() dry-run. `ts-model` is the off-chain TS evaluator.
45
+ * Real permit/deny semantics wiring is a later phase; week-1 returns a
46
+ * clearly-marked stub (empty `evaluations`, `permitted: null`). */
47
+ export interface SimulationResult {
48
+ backend: 'ts-model';
49
+ /** Whether the permit tx would be allowed; null until real semantics land. */
50
+ permitted: boolean | null;
51
+ /** Per-construct evaluation trace; empty placeholder in this slice. */
52
+ evaluations: unknown[];
53
+ /** Diagnostics; marks the stub explicitly. */
54
+ notes: string[];
55
+ }
56
+ /** OUTPUT: compile a PolicyIR to a backend-specific installable policy. */
57
+ export interface CustodyAdapter {
58
+ readonly name: string;
59
+ readonly mode: CustodyMode;
60
+ capabilities(): CustodyCapabilities;
61
+ compile(ir: PolicyIR): CompileResult;
62
+ /** Phase-03 wiring; a clearly-marked stub in week-1. */
63
+ simulate(ir: PolicyIR, permitTx: RecordedTransaction): SimulationResult;
64
+ /** Canonical JSON of the IR (portability / audit). */
65
+ export(ir: PolicyIR): string;
66
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ // src/seams/types.ts - the three custody seams (contracts, not implementations).
3
+ //
4
+ // The synthesizer is decoupled from its edges by three seams:
5
+ // - PolicySource (INPUT): produces a normalized RecordedTransaction. The
6
+ // recorder is the reference source; a MandateSpec
7
+ // lowering is a second, deterministic source.
8
+ // - ChainDecoder (DECODE): chain-specific call data -> normalized facts.
9
+ // - CustodyAdapter (OUTPUT): compile a PolicyIR to a backend-native policy +
10
+ // verify/export it (OZ is the first adapter).
11
+ // These are INTERFACES only. Implementations live in their own modules.
12
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,64 @@
1
+ import type { IRCompOp, PolicyIR } from '../ir/types.ts';
2
+ import type { AmbiguityPrompt, ContractInvocation, Network } from '../types.ts';
3
+ import type { IntentFacts } from './lower.ts';
4
+ /** Per-asset oracle-price bound supplied by the caller (e.g. swap allowed only
5
+ * if oracle_price(XLM) < 5.00 USDC). One entry per asset; the recorder never
6
+ * fabricates a price bound from a slippage value (different units). */
7
+ export interface OraclePriceBound {
8
+ asset: string;
9
+ operator: IRCompOp;
10
+ value: string;
11
+ }
12
+ /** Caller-supplied answers to the ambiguity prompts. Every numeric bound the
13
+ * synth might apply must come from here - the recording supplies observed
14
+ * amounts (offered only as suggestions), never authorised ceilings. */
15
+ export interface ComposeUserResponses {
16
+ /** Rolling window (seconds) for a spending_limit / invocation_count. */
17
+ windowSeconds?: number;
18
+ /** OZ context-rule expiry (ledger sequence). */
19
+ validUntilLedger?: number;
20
+ /** Per-window spend ceiling (i128 decimal string). Required to emit a
21
+ * spending_limit; absent -> AMOUNT_BOUND_MISSING. */
22
+ limitAmount?: string;
23
+ /** Max invocations per window for an incoming-only flow. Required to emit an
24
+ * invocation_count bound; absent -> FREQUENCY_BOUND_MISSING. */
25
+ invocationLimit?: number;
26
+ /** Per-asset oracle-price bound(s). Each entry lowers to a single
27
+ * `oracle_price(asset) OP value` compare in the interpreter IR. Multiple
28
+ * entries on the same asset emit multiple leaves. */
29
+ oraclePriceBound?: OraclePriceBound[];
30
+ /** Recipient allowlist for a swap (call_arg[3] on SoroSwap's
31
+ * swap_exact_tokens_for_tokens). Absent -> RECIPIENT_ALLOWLIST_EMPTY
32
+ * ambiguity (the caller is prompted; proceeding without an allowlist leaves
33
+ * the recipient unconstrained). */
34
+ swapRecipientAllowlist?: string[];
35
+ }
36
+ /** Composition options. */
37
+ export interface ComposeOptions {
38
+ network: Network;
39
+ userResponses?: ComposeUserResponses;
40
+ /** When true, constraints the OZ adapter cannot lower are routed to
41
+ * `interpreterIr` (the predicate-shape IR) so the orchestrator can compile
42
+ * them via the interpreter adapter. When false (the default for callers
43
+ * who have not opted in), every constraint goes to `ir` and the OZ
44
+ * adapter's `uncovered` machinery generates the descriptive warnings -
45
+ * today's behaviour. The orchestrator passes this flag through based on
46
+ * whether `opts.interpreter` was supplied. */
47
+ interpreterEnabled?: boolean;
48
+ }
49
+ /** Result of composition: the OZ-shape PolicyIR, the predicate-shape PolicyIR
50
+ * (contains the constraints the OZ adapter cannot lower; empty when
51
+ * `interpreterEnabled` is false), any ambiguities surfaced during inference,
52
+ * and descriptive warnings for needs that are NOT expressed as an IR node
53
+ * (so no fabricated constraint is emitted). The orchestrator carries
54
+ * ambiguities into `ProposedPolicy.ambiguities` and merges warnings into
55
+ * `ProposedPolicy.warnings`. */
56
+ export interface ComposeResult {
57
+ ir: PolicyIR;
58
+ interpreterIr: PolicyIR;
59
+ ambiguities: AmbiguityPrompt[];
60
+ warnings: string[];
61
+ }
62
+ /** Compose a PolicyIR pair from the lowered facts + the resolved scope.
63
+ * Pure (no randomness, no clock); same inputs -> byte-identical result. */
64
+ export declare function composeFromRecording(facts: IntentFacts, scopeContract: string, topLevel: ContractInvocation | null, opts: ComposeOptions): ComposeResult;