@synapsor/spec 0.1.1 → 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 CHANGED
@@ -67,9 +67,10 @@ synapsor-runner cloud push ./synapsor.contract.json --dry-run
67
67
  - contexts and trusted/session bindings;
68
68
  - resources and subject identity;
69
69
  - read/proposal/external-action capabilities;
70
+ - model-facing capability descriptions and returns hints;
70
71
  - visible and kept-out fields;
71
72
  - evidence/query-audit requirements;
72
- - proposal action shape and guarded writeback intent;
73
+ - proposal action shape, numeric bounds, transition guards, and guarded writeback intent;
73
74
  - workflow allowed capabilities and replay requirements;
74
75
  - policy references and 0.1 policy metadata.
75
76
 
@@ -124,6 +125,23 @@ Allowed prefixes:
124
125
  Unknown unprefixed fields fail validation by design. That keeps Runner, Cloud,
125
126
  C++, and DSL semantics from drifting silently.
126
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
+
127
145
  ## Stability
128
146
 
129
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;
@@ -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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"}
@@ -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;AA2DtF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAiCjE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,gBAAgB,CAGrF"}
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,7 @@
1
+ {
2
+ "ok": false,
3
+ "error": {
4
+ "code": "POLICY_VIOLATION"
5
+ },
6
+ "source_database_changed": false
7
+ }
@@ -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.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",
@@ -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" },