@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.
- package/LICENSE +21 -0
- package/README.md +193 -5
- package/dist/adapters/interpreter/adapter.d.ts +38 -0
- package/dist/adapters/interpreter/adapter.js +522 -0
- package/dist/adapters/interpreter/index.d.ts +1 -0
- package/dist/adapters/interpreter/index.js +2 -0
- package/dist/adapters/oz/adapter.js +2 -0
- package/dist/codegen/compile-gate.d.ts +33 -0
- package/dist/codegen/compile-gate.js +119 -0
- package/dist/codegen/index.d.ts +2 -0
- package/dist/codegen/index.js +8 -0
- package/dist/codegen/template.d.ts +18 -0
- package/dist/codegen/template.js +131 -0
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/ir/types.d.ts +13 -2
- package/dist/predicate/encode.d.ts +10 -0
- package/dist/predicate/encode.js +249 -0
- package/dist/predicate/index.d.ts +1 -0
- package/dist/predicate/index.js +2 -0
- package/dist/record/decode.d.ts +6 -3
- package/dist/record/decode.js +13 -3
- package/dist/review-card/builder.d.ts +14 -0
- package/dist/review-card/builder.js +261 -0
- package/dist/review-card/conflict.d.ts +40 -0
- package/dist/review-card/conflict.js +111 -0
- package/dist/review-card/cross-check.d.ts +11 -0
- package/dist/review-card/cross-check.js +148 -0
- package/dist/review-card/index.d.ts +3 -0
- package/dist/review-card/index.js +4 -0
- package/dist/run/index.d.ts +31 -0
- package/dist/run/index.js +164 -0
- package/dist/run/schemas.d.ts +2003 -0
- package/dist/run/schemas.js +215 -0
- package/dist/synth/compose-from-recording.d.ts +35 -7
- package/dist/synth/compose-from-recording.js +225 -34
- package/dist/synth/deny-cases.d.ts +12 -0
- package/dist/synth/deny-cases.js +377 -0
- package/dist/synth/evaluate.d.ts +39 -0
- package/dist/synth/evaluate.js +425 -0
- package/dist/synth/harness.d.ts +16 -0
- package/dist/synth/harness.js +26 -0
- package/dist/synth/index.d.ts +4 -0
- package/dist/synth/index.js +4 -0
- package/dist/synth/minimize.d.ts +4 -0
- package/dist/synth/minimize.js +38 -0
- package/dist/synth/predicate-literals.d.ts +5 -0
- package/dist/synth/predicate-literals.js +25 -0
- package/dist/synth/synthesize-from-recording.d.ts +37 -5
- package/dist/synth/synthesize-from-recording.js +550 -18
- package/dist/types.d.ts +40 -1
- package/dist/types.js +17 -0
- package/dist/verify/envelope.d.ts +15 -0
- package/dist/verify/envelope.js +22 -0
- package/dist/verify/index.d.ts +3 -0
- package/dist/verify/index.js +3 -0
- package/dist/verify/simulate.d.ts +31 -0
- package/dist/verify/simulate.js +258 -0
- package/dist/verify/verify.d.ts +21 -0
- package/dist/verify/verify.js +189 -0
- package/dist-cjs/adapters/interpreter/adapter.d.ts +38 -0
- package/dist-cjs/adapters/interpreter/adapter.js +527 -0
- package/dist-cjs/adapters/interpreter/index.d.ts +1 -0
- package/dist-cjs/adapters/interpreter/index.js +8 -0
- package/dist-cjs/adapters/oz/adapter.d.ts +20 -0
- package/dist-cjs/adapters/oz/adapter.js +289 -0
- package/dist-cjs/adapters/oz/index.d.ts +1 -0
- package/dist-cjs/adapters/oz/index.js +8 -0
- package/dist-cjs/codegen/compile-gate.d.ts +33 -0
- package/dist-cjs/codegen/compile-gate.js +123 -0
- package/dist-cjs/codegen/index.d.ts +2 -0
- package/dist-cjs/codegen/index.js +14 -0
- package/dist-cjs/codegen/template.d.ts +18 -0
- package/dist-cjs/codegen/template.js +134 -0
- package/dist-cjs/errors.d.ts +37 -0
- package/dist-cjs/errors.js +3 -0
- package/dist-cjs/index.d.ts +11 -0
- package/dist-cjs/index.js +27 -0
- package/dist-cjs/ir/index.d.ts +1 -0
- package/dist-cjs/ir/index.js +3 -0
- package/dist-cjs/ir/types.d.ts +108 -0
- package/dist-cjs/ir/types.js +12 -0
- package/dist-cjs/mandate/index.d.ts +2 -0
- package/dist-cjs/mandate/index.js +6 -0
- package/dist-cjs/mandate/to-ir.d.ts +3 -0
- package/dist-cjs/mandate/to-ir.js +63 -0
- package/dist-cjs/mandate/types.d.ts +20 -0
- package/dist-cjs/mandate/types.js +9 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/predicate/encode.d.ts +10 -0
- package/dist-cjs/predicate/encode.js +252 -0
- package/dist-cjs/predicate/index.d.ts +1 -0
- package/dist-cjs/predicate/index.js +6 -0
- package/dist-cjs/record/decode.d.ts +79 -0
- package/dist-cjs/record/decode.js +398 -0
- package/dist-cjs/record/freshness.d.ts +17 -0
- package/dist-cjs/record/freshness.js +55 -0
- package/dist-cjs/record/index.d.ts +21 -0
- package/dist-cjs/record/index.js +166 -0
- package/dist-cjs/record/movements.d.ts +20 -0
- package/dist-cjs/record/movements.js +192 -0
- package/dist-cjs/record/rpc.d.ts +22 -0
- package/dist-cjs/record/rpc.js +74 -0
- package/dist-cjs/record/validate.d.ts +22 -0
- package/dist-cjs/record/validate.js +63 -0
- package/dist-cjs/registry/identify.d.ts +11 -0
- package/dist-cjs/registry/identify.js +87 -0
- package/dist-cjs/registry/index.d.ts +3 -0
- package/dist-cjs/registry/index.js +15 -0
- package/dist-cjs/registry/known-addresses.d.ts +16 -0
- package/dist-cjs/registry/known-addresses.js +53 -0
- package/dist-cjs/registry/protocols.d.ts +38 -0
- package/dist-cjs/registry/protocols.js +153 -0
- package/dist-cjs/review-card/builder.d.ts +14 -0
- package/dist-cjs/review-card/builder.js +264 -0
- package/dist-cjs/review-card/conflict.d.ts +40 -0
- package/dist-cjs/review-card/conflict.js +114 -0
- package/dist-cjs/review-card/cross-check.d.ts +11 -0
- package/dist-cjs/review-card/cross-check.js +151 -0
- package/dist-cjs/review-card/index.d.ts +3 -0
- package/dist-cjs/review-card/index.js +10 -0
- package/dist-cjs/run/index.d.ts +31 -0
- package/dist-cjs/run/index.js +178 -0
- package/dist-cjs/run/schemas.d.ts +2003 -0
- package/dist-cjs/run/schemas.js +218 -0
- package/dist-cjs/seams/index.d.ts +1 -0
- package/dist-cjs/seams/index.js +3 -0
- package/dist-cjs/seams/types.d.ts +66 -0
- package/dist-cjs/seams/types.js +12 -0
- package/dist-cjs/synth/compose-from-recording.d.ts +64 -0
- package/dist-cjs/synth/compose-from-recording.js +356 -0
- package/dist-cjs/synth/deny-cases.d.ts +12 -0
- package/dist-cjs/synth/deny-cases.js +380 -0
- package/dist-cjs/synth/evaluate.d.ts +39 -0
- package/dist-cjs/synth/evaluate.js +428 -0
- package/dist-cjs/synth/harness.d.ts +16 -0
- package/dist-cjs/synth/harness.js +29 -0
- package/dist-cjs/synth/index.d.ts +9 -0
- package/dist-cjs/synth/index.js +23 -0
- package/dist-cjs/synth/lower.d.ts +23 -0
- package/dist-cjs/synth/lower.js +119 -0
- package/dist-cjs/synth/minimize.d.ts +4 -0
- package/dist-cjs/synth/minimize.js +41 -0
- package/dist-cjs/synth/predicate-literals.d.ts +5 -0
- package/dist-cjs/synth/predicate-literals.js +28 -0
- package/dist-cjs/synth/scope.d.ts +26 -0
- package/dist-cjs/synth/scope.js +81 -0
- package/dist-cjs/synth/synthesize-from-mandate.d.ts +5 -0
- package/dist-cjs/synth/synthesize-from-mandate.js +37 -0
- package/dist-cjs/synth/synthesize-from-recording.d.ts +49 -0
- package/dist-cjs/synth/synthesize-from-recording.js +711 -0
- package/dist-cjs/types.d.ts +288 -0
- package/dist-cjs/types.js +55 -0
- package/dist-cjs/verify/envelope.d.ts +15 -0
- package/dist-cjs/verify/envelope.js +23 -0
- package/dist-cjs/verify/index.d.ts +3 -0
- package/dist-cjs/verify/index.js +8 -0
- package/dist-cjs/verify/simulate.d.ts +31 -0
- package/dist-cjs/verify/simulate.js +261 -0
- package/dist-cjs/verify/verify.d.ts +21 -0
- package/dist-cjs/verify/verify.js +192 -0
- package/package.json +43 -3
- package/src/adapters/interpreter/adapter.ts +642 -0
- package/src/adapters/interpreter/index.ts +8 -0
- package/src/adapters/oz/adapter.ts +2 -0
- package/src/codegen/compile-gate.ts +162 -0
- package/src/codegen/index.ts +17 -0
- package/src/codegen/template.ts +148 -0
- package/src/errors.ts +2 -0
- package/src/index.ts +2 -0
- package/src/ir/types.ts +9 -2
- package/src/predicate/encode.ts +307 -0
- package/src/predicate/index.ts +3 -0
- package/src/record/decode.ts +21 -10
- package/src/review-card/builder.ts +303 -0
- package/src/review-card/conflict.ts +143 -0
- package/src/review-card/cross-check.ts +158 -0
- package/src/review-card/index.ts +12 -0
- package/src/run/index.ts +213 -0
- package/src/run/schemas.ts +242 -0
- package/src/synth/compose-from-recording.ts +277 -43
- package/src/synth/deny-cases.ts +466 -0
- package/src/synth/evaluate.ts +493 -0
- package/src/synth/harness.ts +40 -0
- package/src/synth/index.ts +12 -0
- package/src/synth/minimize.ts +44 -0
- package/src/synth/predicate-literals.ts +27 -0
- package/src/synth/synthesize-from-recording.ts +655 -19
- package/src/types.ts +38 -2
- package/src/verify/envelope.ts +28 -0
- package/src/verify/index.ts +5 -0
- package/src/verify/simulate.ts +311 -0
- 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,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;
|