@synapsor/spec 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +93 -2
- package/fixtures/conformance/numeric-bounds/contract.json +117 -0
- package/fixtures/conformance/numeric-bounds/expected.rejection.json +7 -0
- package/fixtures/conformance/numeric-bounds/scenario.json +21 -0
- package/package.json +10 -1
- package/schemas/synapsor-contract.schema.json +44 -0
package/README.md
CHANGED
|
@@ -7,6 +7,12 @@ Cloud/C++. The contract describes trusted context, business resources,
|
|
|
7
7
|
capabilities, workflows, policies, evidence, proposals, receipts, replay, and
|
|
8
8
|
external action intents.
|
|
9
9
|
|
|
10
|
+
Part of the Synapsor OSS toolchain:
|
|
11
|
+
|
|
12
|
+
- [`@synapsor/runner`](https://www.npmjs.com/package/@synapsor/runner): local MCP runtime that serves validated contracts.
|
|
13
|
+
- [`@synapsor/dsl`](https://www.npmjs.com/package/@synapsor/dsl): SQL-like authoring layer that compiles to this spec.
|
|
14
|
+
- [Source and issues on GitHub](https://github.com/Synapsor/Synapsor-Runner).
|
|
15
|
+
|
|
10
16
|
It does not contain local runtime wiring:
|
|
11
17
|
|
|
12
18
|
- no database URLs;
|
|
@@ -61,9 +67,10 @@ synapsor-runner cloud push ./synapsor.contract.json --dry-run
|
|
|
61
67
|
- contexts and trusted/session bindings;
|
|
62
68
|
- resources and subject identity;
|
|
63
69
|
- read/proposal/external-action capabilities;
|
|
70
|
+
- model-facing capability descriptions and returns hints;
|
|
64
71
|
- visible and kept-out fields;
|
|
65
72
|
- evidence/query-audit requirements;
|
|
66
|
-
- proposal action shape and guarded writeback intent;
|
|
73
|
+
- proposal action shape, numeric bounds, transition guards, and guarded writeback intent;
|
|
67
74
|
- workflow allowed capabilities and replay requirements;
|
|
68
75
|
- policy references and 0.1 policy metadata.
|
|
69
76
|
|
|
@@ -118,6 +125,23 @@ Allowed prefixes:
|
|
|
118
125
|
Unknown unprefixed fields fail validation by design. That keeps Runner, Cloud,
|
|
119
126
|
C++, and DSL semantics from drifting silently.
|
|
120
127
|
|
|
128
|
+
## 0.1 Additive Fields
|
|
129
|
+
|
|
130
|
+
The `0.1` line accepts additive optional core fields when they carry portable
|
|
131
|
+
safety semantics shared by Runner and Cloud/C++.
|
|
132
|
+
|
|
133
|
+
Current additive safety fields:
|
|
134
|
+
|
|
135
|
+
- capability `returns_hint`: model-facing result guidance for a reviewed tool;
|
|
136
|
+
- proposal `numeric_bounds`: reviewed minimum/maximum constraints for patched
|
|
137
|
+
numeric fields;
|
|
138
|
+
- proposal `transition_guards`: reviewed allowed state transitions for patched
|
|
139
|
+
string fields.
|
|
140
|
+
|
|
141
|
+
These are not `x-runner-*` extensions because they are part of the reviewed
|
|
142
|
+
contract. A Cloud importer may choose when to enforce them, but it must not
|
|
143
|
+
silently drop or reject them as unknown runner-only metadata.
|
|
144
|
+
|
|
121
145
|
## Stability
|
|
122
146
|
|
|
123
147
|
`0.1` is the first shared contract line. It is intended to be useful and
|
package/dist/types.d.ts
CHANGED
|
@@ -85,6 +85,14 @@ export type ProposalActionSpec = ExtensionFields & {
|
|
|
85
85
|
action: string;
|
|
86
86
|
allowed_fields: string[];
|
|
87
87
|
patch: Record<string, PatchBindingSpec>;
|
|
88
|
+
numeric_bounds?: Record<string, {
|
|
89
|
+
minimum?: number;
|
|
90
|
+
maximum?: number;
|
|
91
|
+
}>;
|
|
92
|
+
transition_guards?: Record<string, {
|
|
93
|
+
from_column?: string;
|
|
94
|
+
allowed: Record<string, string[]>;
|
|
95
|
+
}>;
|
|
88
96
|
conflict_guard?: {
|
|
89
97
|
column?: string;
|
|
90
98
|
weak_guard_ack?: boolean;
|
|
@@ -102,6 +110,7 @@ export type ProposalActionSpec = ExtensionFields & {
|
|
|
102
110
|
export type CapabilitySpec = ExtensionFields & {
|
|
103
111
|
name: string;
|
|
104
112
|
description?: string;
|
|
113
|
+
returns_hint?: string;
|
|
105
114
|
kind: CapabilityKind;
|
|
106
115
|
context: string;
|
|
107
116
|
source?: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/validate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAmB,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAmB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6DtF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAiCjE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,gBAAgB,CAGrF"}
|
package/dist/validate.js
CHANGED
|
@@ -19,13 +19,15 @@ const METADATA_KEYS = new Set(["name", "description", "version", "tags"]);
|
|
|
19
19
|
const RESOURCE_KEYS = new Set(["name", "engine", "schema", "table", "type", "primary_key", "tenant_key", "conflict_key", "single_tenant_dev"]);
|
|
20
20
|
const CONTEXT_KEYS = new Set(["name", "description", "bindings", "tenant_binding", "principal_binding"]);
|
|
21
21
|
const BINDING_KEYS = new Set(["name", "source", "key", "required"]);
|
|
22
|
-
const CAPABILITY_KEYS = new Set(["name", "description", "kind", "context", "source", "subject", "args", "lookup", "visible_fields", "kept_out_fields", "evidence", "max_rows", "proposal"]);
|
|
22
|
+
const CAPABILITY_KEYS = new Set(["name", "description", "returns_hint", "kind", "context", "source", "subject", "args", "lookup", "visible_fields", "kept_out_fields", "evidence", "max_rows", "proposal"]);
|
|
23
23
|
const SUBJECT_KEYS = new Set(["resource", "schema", "table", "primary_key", "tenant_key", "conflict_key", "single_tenant_dev"]);
|
|
24
24
|
const ARG_KEYS = new Set(["type", "description", "required", "max_length", "minimum", "maximum", "enum"]);
|
|
25
25
|
const LOOKUP_KEYS = new Set(["id_from_arg"]);
|
|
26
26
|
const EVIDENCE_KEYS = new Set(["required", "sources", "query_audit", "handle_prefix"]);
|
|
27
|
-
const PROPOSAL_KEYS = new Set(["action", "allowed_fields", "patch", "conflict_guard", "approval", "writeback"]);
|
|
27
|
+
const PROPOSAL_KEYS = new Set(["action", "allowed_fields", "patch", "numeric_bounds", "transition_guards", "conflict_guard", "approval", "writeback"]);
|
|
28
28
|
const PATCH_KEYS = new Set(["fixed", "from_arg"]);
|
|
29
|
+
const NUMERIC_BOUND_KEYS = new Set(["minimum", "maximum"]);
|
|
30
|
+
const TRANSITION_GUARD_KEYS = new Set(["from_column", "allowed"]);
|
|
29
31
|
const CONFLICT_GUARD_KEYS = new Set(["column", "weak_guard_ack"]);
|
|
30
32
|
const APPROVAL_KEYS = new Set(["mode", "required_role"]);
|
|
31
33
|
const WRITEBACK_KEYS = new Set(["mode", "executor", "idempotency_key"]);
|
|
@@ -204,6 +206,8 @@ function validateCapabilities(value, contextNames, resourceNames, errors, warnin
|
|
|
204
206
|
errors.push({ path: `${path}.name`, code: "INVALID_CAPABILITY_NAME", message: "capability name must be namespace.name." });
|
|
205
207
|
else
|
|
206
208
|
addUnique(names, capability.name, `${path}.name`, "DUPLICATE_CAPABILITY_NAME", errors);
|
|
209
|
+
if (capability.returns_hint !== undefined && !isNonEmptyString(capability.returns_hint))
|
|
210
|
+
errors.push({ path: `${path}.returns_hint`, code: "INVALID_RETURNS_HINT", message: "returns_hint must be a non-empty string." });
|
|
207
211
|
if (!["read", "proposal", "external_action", "answer_with_evidence"].includes(String(capability.kind)))
|
|
208
212
|
errors.push({ path: `${path}.kind`, code: "INVALID_CAPABILITY_KIND", message: "kind must be read, proposal, external_action, or answer_with_evidence." });
|
|
209
213
|
if (!isNonEmptyString(capability.context) || !contextNames.has(capability.context))
|
|
@@ -266,6 +270,20 @@ function validateArgs(value, path, errors) {
|
|
|
266
270
|
checkUnknownKeys(arg, ARG_KEYS, argPath, errors);
|
|
267
271
|
if (!["string", "number", "boolean"].includes(String(arg.type)))
|
|
268
272
|
errors.push({ path: `${argPath}.type`, code: "INVALID_ARG_TYPE", message: "arg type must be string, number, or boolean." });
|
|
273
|
+
if (arg.description !== undefined && !isNonEmptyString(arg.description))
|
|
274
|
+
errors.push({ path: `${argPath}.description`, code: "INVALID_ARG_DESCRIPTION", message: "arg description must be a non-empty string." });
|
|
275
|
+
if (arg.max_length !== undefined && (!Number.isInteger(arg.max_length) || Number(arg.max_length) <= 0))
|
|
276
|
+
errors.push({ path: `${argPath}.max_length`, code: "INVALID_MAX_LENGTH", message: "max_length must be a positive integer." });
|
|
277
|
+
if ((arg.minimum !== undefined || arg.maximum !== undefined) && arg.type !== "number")
|
|
278
|
+
errors.push({ path: argPath, code: "NUMERIC_BOUNDS_REQUIRE_NUMBER", message: "minimum/maximum can only be used with number args." });
|
|
279
|
+
if (arg.minimum !== undefined && !isFiniteNumber(arg.minimum))
|
|
280
|
+
errors.push({ path: `${argPath}.minimum`, code: "INVALID_MINIMUM", message: "minimum must be a finite number." });
|
|
281
|
+
if (arg.maximum !== undefined && !isFiniteNumber(arg.maximum))
|
|
282
|
+
errors.push({ path: `${argPath}.maximum`, code: "INVALID_MAXIMUM", message: "maximum must be a finite number." });
|
|
283
|
+
if (isFiniteNumber(arg.minimum) && isFiniteNumber(arg.maximum) && Number(arg.minimum) > Number(arg.maximum))
|
|
284
|
+
errors.push({ path: argPath, code: "INVALID_ARG_NUMERIC_RANGE", message: "minimum must be less than or equal to maximum." });
|
|
285
|
+
if (arg.enum !== undefined && (!Array.isArray(arg.enum) || arg.enum.length === 0))
|
|
286
|
+
errors.push({ path: `${argPath}.enum`, code: "INVALID_ARG_ENUM", message: "enum must be a non-empty array when provided." });
|
|
269
287
|
}
|
|
270
288
|
}
|
|
271
289
|
function validateLookup(value, path, args, errors) {
|
|
@@ -317,6 +335,8 @@ function validateProposalAction(value, path, errors) {
|
|
|
317
335
|
errors.push({ path: patchPath, code: "PATCH_BINDING_REQUIRED", message: "patch binding must include fixed or from_arg." });
|
|
318
336
|
}
|
|
319
337
|
}
|
|
338
|
+
validateNumericBounds(value.numeric_bounds, value.patch, `${path}.numeric_bounds`, errors);
|
|
339
|
+
validateTransitionGuards(value.transition_guards, value.patch, `${path}.transition_guards`, errors);
|
|
320
340
|
if (value.conflict_guard !== undefined) {
|
|
321
341
|
if (!isRecord(value.conflict_guard))
|
|
322
342
|
errors.push({ path: `${path}.conflict_guard`, code: "CONFLICT_GUARD_NOT_OBJECT", message: "conflict_guard must be an object." });
|
|
@@ -336,6 +356,74 @@ function validateProposalAction(value, path, errors) {
|
|
|
336
356
|
errors.push({ path: `${path}.writeback.mode`, code: "INVALID_WRITEBACK_MODE", message: "writeback.mode must be direct_sql, app_handler, cloud_worker, or none." });
|
|
337
357
|
}
|
|
338
358
|
}
|
|
359
|
+
function validateNumericBounds(value, patch, path, errors) {
|
|
360
|
+
if (value === undefined)
|
|
361
|
+
return;
|
|
362
|
+
if (!isRecord(value)) {
|
|
363
|
+
errors.push({ path, code: "NUMERIC_BOUNDS_NOT_OBJECT", message: "numeric_bounds must map patch fields to numeric bounds." });
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const patchFields = isRecord(patch) ? new Set(Object.keys(patch)) : new Set();
|
|
367
|
+
for (const [field, bounds] of Object.entries(value)) {
|
|
368
|
+
const boundPath = `${path}.${field}`;
|
|
369
|
+
if (!isSafeIdentifier(field))
|
|
370
|
+
errors.push({ path: boundPath, code: "INVALID_NUMERIC_BOUND_FIELD", message: "numeric_bounds keys must be safe patch fields." });
|
|
371
|
+
if (!patchFields.has(field))
|
|
372
|
+
errors.push({ path: boundPath, code: "NUMERIC_BOUND_PATCH_FIELD_REQUIRED", message: "numeric_bounds can only constrain fields in proposal.patch." });
|
|
373
|
+
if (!isRecord(bounds)) {
|
|
374
|
+
errors.push({ path: boundPath, code: "NUMERIC_BOUND_NOT_OBJECT", message: "numeric bound must be an object." });
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
checkUnknownKeys(bounds, NUMERIC_BOUND_KEYS, boundPath, errors);
|
|
378
|
+
const hasMinimum = bounds.minimum !== undefined;
|
|
379
|
+
const hasMaximum = bounds.maximum !== undefined;
|
|
380
|
+
if (!hasMinimum && !hasMaximum)
|
|
381
|
+
errors.push({ path: boundPath, code: "NUMERIC_BOUND_EMPTY", message: "numeric bound must define minimum, maximum, or both." });
|
|
382
|
+
if (hasMinimum && !isFiniteNumber(bounds.minimum))
|
|
383
|
+
errors.push({ path: `${boundPath}.minimum`, code: "INVALID_MINIMUM", message: "minimum must be a finite number." });
|
|
384
|
+
if (hasMaximum && !isFiniteNumber(bounds.maximum))
|
|
385
|
+
errors.push({ path: `${boundPath}.maximum`, code: "INVALID_MAXIMUM", message: "maximum must be a finite number." });
|
|
386
|
+
if (isFiniteNumber(bounds.minimum) && isFiniteNumber(bounds.maximum) && Number(bounds.minimum) > Number(bounds.maximum)) {
|
|
387
|
+
errors.push({ path: boundPath, code: "INVALID_NUMERIC_RANGE", message: "minimum must be less than or equal to maximum." });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function validateTransitionGuards(value, patch, path, errors) {
|
|
392
|
+
if (value === undefined)
|
|
393
|
+
return;
|
|
394
|
+
if (!isRecord(value)) {
|
|
395
|
+
errors.push({ path, code: "TRANSITION_GUARDS_NOT_OBJECT", message: "transition_guards must map patch fields to allowed state transitions." });
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const patchFields = isRecord(patch) ? new Set(Object.keys(patch)) : new Set();
|
|
399
|
+
for (const [field, guard] of Object.entries(value)) {
|
|
400
|
+
const guardPath = `${path}.${field}`;
|
|
401
|
+
if (!isSafeIdentifier(field))
|
|
402
|
+
errors.push({ path: guardPath, code: "INVALID_TRANSITION_GUARD_FIELD", message: "transition_guards keys must be safe patch fields." });
|
|
403
|
+
if (!patchFields.has(field))
|
|
404
|
+
errors.push({ path: guardPath, code: "TRANSITION_GUARD_PATCH_FIELD_REQUIRED", message: "transition_guards can only constrain fields in proposal.patch." });
|
|
405
|
+
if (!isRecord(guard)) {
|
|
406
|
+
errors.push({ path: guardPath, code: "TRANSITION_GUARD_NOT_OBJECT", message: "transition guard must be an object." });
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
checkUnknownKeys(guard, TRANSITION_GUARD_KEYS, guardPath, errors);
|
|
410
|
+
if (guard.from_column !== undefined && !isSafeIdentifier(guard.from_column)) {
|
|
411
|
+
errors.push({ path: `${guardPath}.from_column`, code: "INVALID_TRANSITION_FROM_COLUMN", message: "from_column must be a safe identifier." });
|
|
412
|
+
}
|
|
413
|
+
if (!isRecord(guard.allowed) || Object.keys(guard.allowed).length === 0) {
|
|
414
|
+
errors.push({ path: `${guardPath}.allowed`, code: "TRANSITION_ALLOWED_REQUIRED", message: "transition guard must define allowed transitions." });
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
for (const [from, toValues] of Object.entries(guard.allowed)) {
|
|
418
|
+
const allowedPath = `${guardPath}.allowed.${from}`;
|
|
419
|
+
if (!isNonEmptyString(from))
|
|
420
|
+
errors.push({ path: allowedPath, code: "TRANSITION_FROM_REQUIRED", message: "transition source state must be a non-empty string." });
|
|
421
|
+
if (!Array.isArray(toValues) || toValues.length === 0 || toValues.some((item) => !isNonEmptyString(item))) {
|
|
422
|
+
errors.push({ path: allowedPath, code: "TRANSITION_TO_VALUES_REQUIRED", message: "transition target states must be non-empty strings." });
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
339
427
|
function validateWorkflows(value, contextNames, capabilityNames, errors) {
|
|
340
428
|
if (value === undefined)
|
|
341
429
|
return;
|
|
@@ -520,3 +608,6 @@ function isQualifiedOrSafeName(value) {
|
|
|
520
608
|
function isPositiveInteger(value) {
|
|
521
609
|
return Number.isInteger(value) && Number(value) > 0;
|
|
522
610
|
}
|
|
611
|
+
function isFiniteNumber(value) {
|
|
612
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
613
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"spec_version": "0.1",
|
|
3
|
+
"kind": "SynapsorContract",
|
|
4
|
+
"metadata": {
|
|
5
|
+
"name": "numeric bounds proposal conformance"
|
|
6
|
+
},
|
|
7
|
+
"resources": [
|
|
8
|
+
{
|
|
9
|
+
"name": "support_accounts",
|
|
10
|
+
"engine": "postgres",
|
|
11
|
+
"schema": "public",
|
|
12
|
+
"table": "accounts",
|
|
13
|
+
"primary_key": "id",
|
|
14
|
+
"tenant_key": "tenant_id",
|
|
15
|
+
"conflict_key": "updated_at"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"contexts": [
|
|
19
|
+
{
|
|
20
|
+
"name": "local_operator",
|
|
21
|
+
"bindings": [
|
|
22
|
+
{
|
|
23
|
+
"name": "tenant_id",
|
|
24
|
+
"source": "environment",
|
|
25
|
+
"key": "SYNAPSOR_TENANT_ID"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "principal",
|
|
29
|
+
"source": "environment",
|
|
30
|
+
"key": "SYNAPSOR_PRINCIPAL"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"tenant_binding": "tenant_id",
|
|
34
|
+
"principal_binding": "principal"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"capabilities": [
|
|
38
|
+
{
|
|
39
|
+
"name": "support.propose_plan_credit",
|
|
40
|
+
"kind": "proposal",
|
|
41
|
+
"description": "Propose a support credit for a verified outage impact.",
|
|
42
|
+
"returns_hint": "Returns the proposal id and requested credit; DB unchanged.",
|
|
43
|
+
"context": "local_operator",
|
|
44
|
+
"source": "local_postgres",
|
|
45
|
+
"subject": {
|
|
46
|
+
"resource": "support_accounts"
|
|
47
|
+
},
|
|
48
|
+
"args": {
|
|
49
|
+
"account_id": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"required": true,
|
|
52
|
+
"max_length": 128,
|
|
53
|
+
"description": "Account id."
|
|
54
|
+
},
|
|
55
|
+
"amount_cents": {
|
|
56
|
+
"type": "number",
|
|
57
|
+
"required": true,
|
|
58
|
+
"minimum": 1,
|
|
59
|
+
"maximum": 1000000,
|
|
60
|
+
"description": "Credit amount in cents."
|
|
61
|
+
},
|
|
62
|
+
"reason": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"required": true,
|
|
65
|
+
"max_length": 500,
|
|
66
|
+
"description": "Business reason for the credit."
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"lookup": {
|
|
70
|
+
"id_from_arg": "account_id"
|
|
71
|
+
},
|
|
72
|
+
"visible_fields": [
|
|
73
|
+
"id",
|
|
74
|
+
"tenant_id",
|
|
75
|
+
"credit_requested_cents",
|
|
76
|
+
"credit_reason",
|
|
77
|
+
"updated_at"
|
|
78
|
+
],
|
|
79
|
+
"evidence": {
|
|
80
|
+
"required": true,
|
|
81
|
+
"query_audit": true
|
|
82
|
+
},
|
|
83
|
+
"max_rows": 1,
|
|
84
|
+
"proposal": {
|
|
85
|
+
"action": "grant_plan_credit",
|
|
86
|
+
"allowed_fields": [
|
|
87
|
+
"credit_requested_cents",
|
|
88
|
+
"credit_reason"
|
|
89
|
+
],
|
|
90
|
+
"patch": {
|
|
91
|
+
"credit_requested_cents": {
|
|
92
|
+
"from_arg": "amount_cents"
|
|
93
|
+
},
|
|
94
|
+
"credit_reason": {
|
|
95
|
+
"from_arg": "reason"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"numeric_bounds": {
|
|
99
|
+
"credit_requested_cents": {
|
|
100
|
+
"minimum": 1,
|
|
101
|
+
"maximum": 2500
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"conflict_guard": {
|
|
105
|
+
"column": "updated_at"
|
|
106
|
+
},
|
|
107
|
+
"approval": {
|
|
108
|
+
"mode": "human",
|
|
109
|
+
"required_role": "local_reviewer"
|
|
110
|
+
},
|
|
111
|
+
"writeback": {
|
|
112
|
+
"mode": "none"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"trusted_context": {
|
|
3
|
+
"tenant_id": "acme",
|
|
4
|
+
"principal": "dev_test_user"
|
|
5
|
+
},
|
|
6
|
+
"invoke": {
|
|
7
|
+
"capability": "support.propose_plan_credit",
|
|
8
|
+
"args": {
|
|
9
|
+
"account_id": "acct_3001",
|
|
10
|
+
"amount_cents": 999999,
|
|
11
|
+
"reason": "outage credit requested"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"source_row": {
|
|
15
|
+
"id": "acct_3001",
|
|
16
|
+
"tenant_id": "acme",
|
|
17
|
+
"credit_requested_cents": 0,
|
|
18
|
+
"credit_reason": null,
|
|
19
|
+
"updated_at": "2026-06-20T14:31:08Z"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapsor/spec",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Canonical Synapsor contract schemas, types, validation, and conformance fixtures.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -30,6 +30,15 @@
|
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/Synapsor/Synapsor-Runner.git",
|
|
36
|
+
"directory": "packages/spec"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/Synapsor/Synapsor-Runner/tree/main/packages/spec#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/Synapsor/Synapsor-Runner/issues"
|
|
41
|
+
},
|
|
33
42
|
"scripts": {
|
|
34
43
|
"build": "tsc -b",
|
|
35
44
|
"test": "vitest run"
|
|
@@ -205,6 +205,14 @@
|
|
|
205
205
|
"action": { "$ref": "#/$defs/qualifiedOrSafeName" },
|
|
206
206
|
"allowed_fields": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/safeIdentifier" } },
|
|
207
207
|
"patch": { "type": "object", "additionalProperties": { "$ref": "#/$defs/patchBinding" } },
|
|
208
|
+
"numeric_bounds": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"additionalProperties": { "$ref": "#/$defs/numericBound" }
|
|
211
|
+
},
|
|
212
|
+
"transition_guards": {
|
|
213
|
+
"type": "object",
|
|
214
|
+
"additionalProperties": { "$ref": "#/$defs/transitionGuard" }
|
|
215
|
+
},
|
|
208
216
|
"conflict_guard": {
|
|
209
217
|
"type": "object",
|
|
210
218
|
"additionalProperties": false,
|
|
@@ -233,6 +241,41 @@
|
|
|
233
241
|
}
|
|
234
242
|
}
|
|
235
243
|
},
|
|
244
|
+
"numericBound": {
|
|
245
|
+
"type": "object",
|
|
246
|
+
"additionalProperties": false,
|
|
247
|
+
"patternProperties": {
|
|
248
|
+
"^x-(cloud|runner|experimental)-[A-Za-z0-9_.-]+$": true
|
|
249
|
+
},
|
|
250
|
+
"properties": {
|
|
251
|
+
"minimum": { "type": "number" },
|
|
252
|
+
"maximum": { "type": "number" }
|
|
253
|
+
},
|
|
254
|
+
"anyOf": [
|
|
255
|
+
{ "required": ["minimum"] },
|
|
256
|
+
{ "required": ["maximum"] }
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
"transitionGuard": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"required": ["allowed"],
|
|
262
|
+
"additionalProperties": false,
|
|
263
|
+
"patternProperties": {
|
|
264
|
+
"^x-(cloud|runner|experimental)-[A-Za-z0-9_.-]+$": true
|
|
265
|
+
},
|
|
266
|
+
"properties": {
|
|
267
|
+
"from_column": { "$ref": "#/$defs/safeIdentifier" },
|
|
268
|
+
"allowed": {
|
|
269
|
+
"type": "object",
|
|
270
|
+
"minProperties": 1,
|
|
271
|
+
"additionalProperties": {
|
|
272
|
+
"type": "array",
|
|
273
|
+
"minItems": 1,
|
|
274
|
+
"items": { "type": "string", "minLength": 1 }
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
},
|
|
236
279
|
"capability": {
|
|
237
280
|
"type": "object",
|
|
238
281
|
"required": ["name", "kind", "context", "subject", "args", "visible_fields"],
|
|
@@ -243,6 +286,7 @@
|
|
|
243
286
|
"properties": {
|
|
244
287
|
"name": { "$ref": "#/$defs/qualifiedName" },
|
|
245
288
|
"description": { "type": "string" },
|
|
289
|
+
"returns_hint": { "type": "string", "minLength": 1 },
|
|
246
290
|
"kind": { "enum": ["read", "proposal", "external_action", "answer_with_evidence"] },
|
|
247
291
|
"context": { "$ref": "#/$defs/qualifiedOrSafeName" },
|
|
248
292
|
"source": { "$ref": "#/$defs/qualifiedOrSafeName" },
|