@synapsor/runner 1.4.12 → 1.4.122

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 (48) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +63 -60
  3. package/THREAT_MODEL.md +6 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/runner.mjs +29227 -2475
  7. package/docs/README.md +11 -0
  8. package/docs/aggregate-reads.md +49 -0
  9. package/docs/bounded-set-writeback.md +9 -4
  10. package/docs/capability-authoring.md +43 -1
  11. package/docs/cloud-cli.md +248 -0
  12. package/docs/cloud-mode.md +88 -6
  13. package/docs/cloud-push.md +22 -5
  14. package/docs/compliance-reports.md +42 -0
  15. package/docs/conformance.md +15 -0
  16. package/docs/contract-review.md +57 -0
  17. package/docs/contract-testing.md +76 -0
  18. package/docs/dsl-reference.md +50 -6
  19. package/docs/graduated-trust.md +64 -0
  20. package/docs/hosted-cloud-linked-verification.md +97 -0
  21. package/docs/limitations.md +10 -0
  22. package/docs/oss-vs-cloud.md +13 -6
  23. package/docs/release-notes.md +65 -0
  24. package/docs/rfcs/007-trusted-principal-row-scope.md +75 -0
  25. package/docs/runner-bundles.md +24 -0
  26. package/docs/runner-config-reference.md +16 -0
  27. package/docs/running-a-runner-fleet.md +8 -0
  28. package/docs/security-boundary.md +28 -1
  29. package/examples/runner-fleet/seed/mysql.sql +5 -1
  30. package/examples/runner-fleet/seed/postgres.sql +5 -1
  31. package/examples/support-plan-credit/README.md +8 -6
  32. package/examples/support-plan-credit/synapsor.contract-tests.json +53 -0
  33. package/fixtures/dsl/aggregate-read.synapsor.sql +21 -0
  34. package/fixtures/dsl/bounded-set-multi-term.synapsor.sql +30 -0
  35. package/fixtures/dsl/principal-row-scope.synapsor.sql +23 -0
  36. package/fixtures/protocol/MANIFEST.json +10 -10
  37. package/package.json +4 -1
  38. package/schemas/change-set.v1.schema.json +14 -0
  39. package/schemas/change-set.v2.schema.json +14 -0
  40. package/schemas/change-set.v3.schema.json +2 -0
  41. package/schemas/compensation-change-set.v1.schema.json +3 -2
  42. package/schemas/inverse-descriptor.v1.schema.json +2 -0
  43. package/schemas/synapsor.contract-tests.schema.json +54 -0
  44. package/schemas/synapsor.runner.schema.json +92 -4
  45. package/schemas/writeback-job.v1.schema.json +14 -0
  46. package/schemas/writeback-job.v2.schema.json +14 -0
  47. package/schemas/writeback-job.v3.schema.json +2 -0
  48. package/schemas/writeback-job.v4.schema.json +2 -2
@@ -38,6 +38,7 @@ Unknown keys fail when `strict` is true (the default).
38
38
  | `session_auth` | HTTP claims | HS256 development or asymmetric RS256/ES256 session-token verification. |
39
39
  | `rate_limits` | No | Operational fixed-window limits; fleet-wide only with shared `runtime_store`. |
40
40
  | `metrics` | No | Separately authorized scrapeable HTTP metrics. Disabled by default. |
41
+ | `graduated_trust` | No | Off-by-default, operator-only policy recommendation criteria and kill switch. |
41
42
  | `executors` | No | App-owned writeback wiring. |
42
43
  | `cloud` | Cloud mode | Scoped Cloud adapter configuration. |
43
44
 
@@ -375,6 +376,21 @@ metrics token; the MCP bearer does not authorize metrics. Labels are bounded to
375
376
  trusted tenant, capability, source, engine, and readiness component. Object
376
377
  IDs, principals, URLs, tokens, and raw errors are never labels.
377
378
 
379
+ ## Graduated trust
380
+
381
+ `graduated_trust` is runtime/operator policy, not model-facing authority. It is
382
+ disabled unless `enabled` is exactly `true`; `kill_switch: true` stops all
383
+ evaluation. Each criterion fixes one capability, approval policy, numeric
384
+ field, minimum human-reviewed sample (10..10000), window (1..365 days), maximum
385
+ rejection/conflict/failure/revert rates, maximum threshold increment, and
386
+ absolute ceiling. Optional `workspace_id` and `project_id` further scope stored
387
+ recommendations.
388
+
389
+ Auto-approved outcomes never count as human evidence. Recommendation decisions
390
+ require verified operator identity. Approval only permits exporting a new
391
+ contract artifact bound to the current digest/version; Runner never activates
392
+ it. See [Graduated Trust Recommendations](graduated-trust.md).
393
+
378
394
  ## Operator identity
379
395
 
380
396
  Local development compatibility uses an explicitly unverified environment
@@ -132,6 +132,14 @@ Every served capability context must bind tenant and principal from
132
132
  `HTTP_CLAIM`. Runner rejects an environment-bound contract mixed into this
133
133
  server with `TRUSTED_CONTEXT_PROVIDER_CONFLICT` before tools are served.
134
134
 
135
+ For same-tenant per-user rows, declare `PRINCIPAL SCOPE KEY assigned_to` (or
136
+ the corresponding canonical `principal_scope_key`) on the capability. The
137
+ signed `sub` claim then becomes a bound SQL predicate composed with the signed
138
+ tenant claim. Session token fingerprint pinning prevents swapping identities
139
+ within an MCP session. `tools preview` displays both locks, and
140
+ `corepack pnpm test:principal-scope` proves two concurrent principals cannot
141
+ read each other's rows or evidence handles on Postgres and MySQL.
142
+
135
143
  Use an HTTPS JWKS URL from an allowlisted identity system. Runner rejects
136
144
  redirects, oversized responses, unknown algorithms, `none`, missing/unknown
137
145
  `kid`, bad issuer/audience, expired/not-yet-valid tokens, and private JWK
@@ -40,10 +40,30 @@ The model does not receive:
40
40
  - commit/writeback tools;
41
41
  - trusted tenant or principal authority as ordinary model arguments.
42
42
 
43
+ Reviewed aggregate tools expose one scalar only. Their function, column,
44
+ tenant key, optional equality selection, and minimum-group threshold are fixed
45
+ in the contract; the model receives no predicate arguments or member rows.
46
+ Suppression reduces single-record inference but does not replace statistical
47
+ privacy review. See [Bounded Aggregate Reads](aggregate-reads.md).
48
+
43
49
  Trusted context comes from local configuration, environment bindings, or Cloud
44
50
  session context in Cloud mode. Tenant, principal, and authorization scope must
45
51
  not be accepted from the model as authority.
46
52
 
53
+ A capability may declare `principal_scope_key` (DSL: `PRINCIPAL SCOPE KEY`) to
54
+ narrow rows inside a tenant. Runner then adds both fixed, parameterized guards:
55
+
56
+ ```text
57
+ tenant_key = verified tenant AND principal_scope_key = verified principal
58
+ ```
59
+
60
+ This applies to single-row reads and writes, aggregates, bounded sets, inserts,
61
+ deletes, executor envelopes, and reviewed compensation. Missing principal
62
+ context fails closed. A principal lock never replaces tenant scope and has no
63
+ dynamic supervisor bypass. Use a separately reviewed tenant-wide capability
64
+ for broader roles. RLS and restricted database roles remain valuable defense in
65
+ depth; the contract does not replace them.
66
+
47
67
  Proposal, evidence, and replay handles are references, not bearer credentials.
48
68
  Before returning a local MCP resource, Runner resolves the resource's owning
49
69
  capability context again and requires both tenant and principal to match the
@@ -70,7 +90,7 @@ outside the model-facing MCP server and verifies:
70
90
  - local approval state;
71
91
  - proposal and job digests;
72
92
  - target schema/table;
73
- - primary-key and tenant guards;
93
+ - primary-key, tenant, and declared principal-row guards;
74
94
  - allowed mutable columns;
75
95
  - conflict/version guard;
76
96
  - idempotency key;
@@ -121,6 +141,13 @@ approve/reject actions. It does not expose raw SQL, database URLs, write
121
141
  credentials, approval tools, commit tools, or controls that widen reviewed
122
142
  tables/columns.
123
143
 
144
+ Contract lint and tests are review aids rather than a proof of complete
145
+ security. Scoped report exports omit evidence rows and kept-out values and are
146
+ tamper-evident when their digest/signature verifies; local SQLite is not an
147
+ immutable compliance service. Graduated-trust evaluation is operator-only,
148
+ disabled by default, and can recommend/export a separate artifact but cannot
149
+ approve itself or activate policy.
150
+
124
151
  Synapsor Runner supports reviewed single-row CRUD and the narrowly bounded set
125
152
  path documented above. It does not support arbitrary SQL, DDL, UPSERT,
126
153
  model-generated predicates, unbounded sets, or cross-table direct writeback.
@@ -4,6 +4,7 @@ CREATE TABLE invoices (
4
4
  status varchar(64) NOT NULL,
5
5
  late_fee_cents integer NOT NULL,
6
6
  waiver_reason varchar(500),
7
+ assigned_to varchar(128) NOT NULL DEFAULT 'case_manager_a',
7
8
  updated_at datetime(6) NOT NULL
8
9
  );
9
10
 
@@ -41,7 +42,10 @@ INSERT INTO guard_crud_items (id, tenant_id, request_id, value_cents, version) V
41
42
  ALTER TABLE guard_crud_items AUTO_INCREMENT = 2001;
42
43
 
43
44
  INSERT INTO invoices (id, tenant_id, status, late_fee_cents, waiver_reason, updated_at) VALUES
44
- ('MYSQL-ACME', 'acme', 'overdue', 700, NULL, '2026-07-12 12:00:00.000000');
45
+ ('MYSQL-ACME', 'acme', 'overdue', 700, NULL, '2026-07-12 12:00:00.000000'),
46
+ ('MYSQL-PRINCIPAL-A', 'hospital_a', 'principal_fixture', 100, NULL, '2026-07-12 12:00:00.000000'),
47
+ ('MYSQL-PRINCIPAL-B', 'hospital_a', 'principal_fixture', 200, NULL, '2026-07-12 12:00:00.000000');
48
+ UPDATE invoices SET assigned_to = 'case_manager_b' WHERE id = 'MYSQL-PRINCIPAL-B';
45
49
 
46
50
  CREATE VIEW slow_invoices AS
47
51
  SELECT invoices.*, SLEEP(0.35) AS synthetic_delay
@@ -4,6 +4,7 @@ CREATE TABLE public.invoices (
4
4
  status text NOT NULL,
5
5
  late_fee_cents integer NOT NULL,
6
6
  waiver_reason text,
7
+ assigned_to text NOT NULL DEFAULT 'case_manager_a',
7
8
  updated_at timestamptz NOT NULL
8
9
  );
9
10
 
@@ -73,7 +74,10 @@ INSERT INTO public.invoices (id, tenant_id, status, late_fee_cents, waiver_reaso
73
74
  ('INV-DEAD-DISCARD', 'acme', 'overdue', 1750, NULL, '2026-07-12T12:00:00Z'),
74
75
  ('INV-KILL-BEFORE', 'acme', 'overdue', 1200, NULL, '2026-07-12T12:00:00Z'),
75
76
  ('INV-KILL-DURING', 'acme', 'overdue', 1500, NULL, '2026-07-12T12:00:00Z'),
76
- ('INV-KILL-AFTER', 'acme', 'overdue', 1800, NULL, '2026-07-12T12:00:00Z');
77
+ ('INV-KILL-AFTER', 'acme', 'overdue', 1800, NULL, '2026-07-12T12:00:00Z'),
78
+ ('INV-PRINCIPAL-A', 'hospital_a', 'principal_fixture', 100, NULL, '2026-07-12T12:00:00Z'),
79
+ ('INV-PRINCIPAL-B', 'hospital_a', 'principal_fixture', 200, NULL, '2026-07-12T12:00:00Z');
80
+ UPDATE public.invoices SET assigned_to = 'case_manager_b' WHERE id = 'INV-PRINCIPAL-B';
77
81
 
78
82
  CREATE FUNCTION public.synthetic_pool_delay() RETURNS integer
79
83
  LANGUAGE plpgsql VOLATILE AS $$
@@ -272,10 +272,12 @@ Real push uses your Cloud env vars:
272
272
 
273
273
  ```bash
274
274
  export SYNAPSOR_CLOUD_BASE_URL="https://api.synapsor.ai"
275
- export SYNAPSOR_CLOUD_TOKEN="<workspace-scoped-token>"
276
- export SYNAPSOR_WORKSPACE_ID="<workspace_id>"
275
+ export SYNAPSOR_API_KEY="<contracts-write-service-key>"
276
+ export SYNAPSOR_PROJECT_ID="<project_id>"
277
+ export SYNAPSOR_SOURCE_ID="<cloud_source_id>"
277
278
 
278
279
  synapsor-runner cloud push examples/support-plan-credit/synapsor.contract.json \
280
+ --workspace "$SYNAPSOR_PROJECT_ID" \
279
281
  --name support-plan-credit
280
282
  ```
281
283
 
@@ -283,11 +285,11 @@ After push, Cloud can return the registered version and a runner bundle with
283
285
  placeholder env names:
284
286
 
285
287
  ```bash
286
- curl -H "Authorization: Bearer $SYNAPSOR_CLOUD_TOKEN" \
287
- "$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_WORKSPACE_ID/agent-contracts/<contract_id>/versions/<version_id>"
288
+ curl -H "Authorization: Bearer $SYNAPSOR_API_KEY" \
289
+ "$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_PROJECT_ID/agent-contracts/<contract_id>/versions/<version_id>"
288
290
 
289
- curl -H "Authorization: Bearer $SYNAPSOR_CLOUD_TOKEN" \
290
- "$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_WORKSPACE_ID/agent-contracts/<contract_id>/versions/<version_id>/runner-bundle?download=1" \
291
+ curl -H "Authorization: Bearer $SYNAPSOR_API_KEY" \
292
+ "$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_PROJECT_ID/agent-contracts/<contract_id>/versions/<version_id>/runner-bundle?download=1&source_id=$SYNAPSOR_SOURCE_ID" \
291
293
  -o support-plan-credit-runner-bundle.zip
292
294
  ```
293
295
 
@@ -0,0 +1,53 @@
1
+ {
2
+ "$schema": "../../schemas/synapsor.contract-tests.schema.json",
3
+ "version": 1,
4
+ "name": "support-plan-credit contract boundary",
5
+ "tests": [
6
+ {
7
+ "id": "operator-controls-stay-outside-mcp",
8
+ "kind": "operator_boundary",
9
+ "capability": "support.propose_plan_credit"
10
+ },
11
+ {
12
+ "id": "private-customer-fields-stay-hidden",
13
+ "kind": "hide_fields",
14
+ "capability": "support.inspect_customer",
15
+ "args": { "customer_id": "CUS-3001" },
16
+ "trusted_context": { "tenant_id": "acme", "principal": "contract_test" },
17
+ "fields": ["card_token", "raw_payment_method", "internal_risk_score", "private_notes"]
18
+ },
19
+ {
20
+ "id": "credit-amount-is-bounded",
21
+ "kind": "argument_constraint",
22
+ "capability": "support.propose_plan_credit_record",
23
+ "argument": "credit_cents",
24
+ "expected": { "minimum": 1, "maximum": 50000 }
25
+ },
26
+ {
27
+ "id": "trusted-tenant-can-read-own-customer",
28
+ "kind": "tool_allow",
29
+ "capability": "support.inspect_customer",
30
+ "args": { "customer_id": "CUS-3001" },
31
+ "trusted_context": { "tenant_id": "acme", "principal": "contract_test" }
32
+ },
33
+ {
34
+ "id": "trusted-tenant-cannot-read-other-customer",
35
+ "kind": "tool_deny",
36
+ "capability": "support.inspect_customer",
37
+ "args": { "customer_id": "CUS-9001" },
38
+ "trusted_context": { "tenant_id": "acme", "principal": "contract_test" },
39
+ "expected_code": "NOT_FOUND_IN_TENANT"
40
+ },
41
+ {
42
+ "id": "proposal-does-not-write-before-approval",
43
+ "kind": "source_unchanged_before_approval",
44
+ "capability": "support.propose_plan_credit",
45
+ "args": {
46
+ "customer_id": "CUS-3001",
47
+ "credit_cents": 10000,
48
+ "reason": "synthetic conformance check"
49
+ },
50
+ "trusted_context": { "tenant_id": "acme", "principal": "contract_test" }
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,21 @@
1
+ CREATE AGENT CONTEXT finance_operator
2
+ BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
3
+ BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
4
+ TENANT BINDING tenant_id
5
+ PRINCIPAL BINDING principal
6
+ END
7
+
8
+ CREATE CAPABILITY billing.overdue_balance_total
9
+ DESCRIPTION 'Return one suppressed overdue-balance aggregate for the trusted tenant.'
10
+ RETURNS HINT 'Returns one scalar or a suppression result; never member rows.'
11
+ USING CONTEXT finance_operator
12
+ SOURCE local_postgres
13
+ ON public.invoices
14
+ PRIMARY KEY id
15
+ TENANT KEY tenant_id
16
+ AGGREGATE READ SUM balance_cents
17
+ SELECT WHERE status = 'overdue'
18
+ MIN GROUP SIZE 5
19
+ KEEP OUT customer_email, private_notes
20
+ REQUIRE EVIDENCE
21
+ END
@@ -0,0 +1,30 @@
1
+ CREATE AGENT CONTEXT local_operator
2
+ BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
3
+ BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
4
+ TENANT BINDING tenant_id
5
+ PRINCIPAL BINDING principal
6
+ END
7
+
8
+ CREATE CAPABILITY cases.close_high_risk
9
+ DESCRIPTION 'Close active high-risk support cases within reviewed row and value caps.'
10
+ RETURNS HINT 'Returns a proposal for the exact reviewed set; source rows remain unchanged.'
11
+ USING CONTEXT local_operator
12
+ SOURCE support_db
13
+ ON public.support_cases
14
+ PRIMARY KEY id
15
+ TENANT KEY tenant_id
16
+ CONFLICT GUARD version
17
+ LOOKUP reason BY id
18
+ ARG reason STRING REQUIRED MAX LENGTH 100
19
+ ALLOW READ id, tenant_id, risk_level, case_status, exposure_cents, version
20
+ REQUIRE EVIDENCE
21
+ PROPOSE ACTION close_high_risk UPDATE SET
22
+ SELECT WHERE risk_level = 'high' AND case_status = 'active'
23
+ MAX ROWS 10
24
+ MAX TOTAL exposure_cents BEFORE 50000
25
+ ALLOW WRITE case_status
26
+ PATCH case_status = 'closed'
27
+ ADVANCE VERSION version USING INTEGER INCREMENT
28
+ APPROVAL ROLE support_manager
29
+ WRITEBACK DIRECT SQL
30
+ END
@@ -0,0 +1,23 @@
1
+ CREATE AGENT CONTEXT care_session
2
+ BIND hospital_id FROM HTTP_CLAIM hospital_id REQUIRED
3
+ BIND principal FROM HTTP_CLAIM sub REQUIRED
4
+ TENANT BINDING hospital_id
5
+ PRINCIPAL BINDING principal
6
+ END
7
+
8
+ CREATE CAPABILITY care.inspect_assigned_patient
9
+ DESCRIPTION 'Inspect one patient assigned to the authenticated case manager within the trusted hospital.'
10
+ RETURNS HINT 'Returns reviewed patient fields and evidence only when both tenant and assignee locks match.'
11
+ USING CONTEXT care_session
12
+ SOURCE local_postgres
13
+ ON public.patients
14
+ PRIMARY KEY id
15
+ TENANT KEY hospital_id
16
+ PRINCIPAL SCOPE KEY assigned_to
17
+ LOOKUP patient_id BY id
18
+ ARG patient_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Reviewed patient identifier.'
19
+ ALLOW READ id, hospital_id, display_name, care_status, updated_at
20
+ KEEP OUT assigned_to, diagnosis_notes, insurance_member_id
21
+ REQUIRE EVIDENCE
22
+ MAX ROWS 1
23
+ END
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "synapsor.protocol-manifest.v1",
3
3
  "protocol_set": "database-mcp-writeback",
4
- "version": "1.4.0",
4
+ "version": "1.4.1",
5
5
  "hash_algorithm": "sha256",
6
6
  "note": "This manifest is copied in Synapsor main protocol/MANIFEST.json and synapsor-runner fixtures/protocol/MANIFEST.json. Hashes are over the checked-in JSON artifact bytes.",
7
7
  "artifacts": [
@@ -113,22 +113,22 @@
113
113
  {
114
114
  "kind": "schema",
115
115
  "name": "change-set.v1.schema.json",
116
- "sha256": "119ac84f7189e9433d4eaac4defb6ef7c459a14e55e1563aa7948b746d816af5"
116
+ "sha256": "18f76efd97424efab986b6fb0af87ad0eeafd4314393ed7f83f14afe09d625eb"
117
117
  },
118
118
  {
119
119
  "kind": "schema",
120
120
  "name": "change-set.v2.schema.json",
121
- "sha256": "cd07204661d08eba31c0cd1f878b881a5b771702de4019f4cf410628384349f8"
121
+ "sha256": "bd9999361258c5554ffa2791d7c6469beffc5b875e775f5f0c80cea36132eaa4"
122
122
  },
123
123
  {
124
124
  "kind": "schema",
125
125
  "name": "change-set.v3.schema.json",
126
- "sha256": "c14a5c787c2a269dfee98911fbba40aaa53fa8d5a007d694366ba8b58e20f0b3"
126
+ "sha256": "24a45eb4d9f29ab4cfe408bedeb0216dc29544fe39b515918d0c0f9742bba9cb"
127
127
  },
128
128
  {
129
129
  "kind": "schema",
130
130
  "name": "compensation-change-set.v1.schema.json",
131
- "sha256": "24585f9c53bd89119bf7a7ea92a587d37fe7dccbf1517d6736b5ecdeff2b9ebc"
131
+ "sha256": "6353ddd1a030d0cd25c1663c96794d5420bc1002f46aacdef58c346238a90450"
132
132
  },
133
133
  {
134
134
  "kind": "schema",
@@ -153,7 +153,7 @@
153
153
  {
154
154
  "kind": "schema",
155
155
  "name": "inverse-descriptor.v1.schema.json",
156
- "sha256": "ae3aa626896bdc114f5368fee4803994852bb5263a24c234f456e05f1d875fd0"
156
+ "sha256": "6f310b11946196cf8c829bcf5be39864d5e3bd85181ae2a3a277bfa6fd72a553"
157
157
  },
158
158
  {
159
159
  "kind": "schema",
@@ -163,22 +163,22 @@
163
163
  {
164
164
  "kind": "schema",
165
165
  "name": "writeback-job.v1.schema.json",
166
- "sha256": "eab35194dd6b6caa7694aa8f14afbf265338d6ee8ed3d3db5d08ec83c4e7092e"
166
+ "sha256": "64238559297805e13c04cb8bf71be433e6fb1241594ca021415b1efb95214a01"
167
167
  },
168
168
  {
169
169
  "kind": "schema",
170
170
  "name": "writeback-job.v2.schema.json",
171
- "sha256": "6f959deedffcb9193b7dffbb0e0beb681bb0b421b6c4460ca14733e3e18acd1f"
171
+ "sha256": "68110a5ed5b7867522cf86db8d177d2df3f96a458a4343bb77537bdcf304279b"
172
172
  },
173
173
  {
174
174
  "kind": "schema",
175
175
  "name": "writeback-job.v3.schema.json",
176
- "sha256": "9ee7992ada437f5df9e1f551e0a16a00db0e98ab5dd745f78848b3e4cdb11cfa"
176
+ "sha256": "3bd46747e737e79bff90dc0496c270bc93d6a913db750ea00486be9a45714831"
177
177
  },
178
178
  {
179
179
  "kind": "schema",
180
180
  "name": "writeback-job.v4.schema.json",
181
- "sha256": "5031e2476ddaf96042c596e76626d8ce8bce2eb51f7167c92bef44d1676a0487"
181
+ "sha256": "2c0d23cdf12f6a0d70c5f38fb4fcc5842f2b6c184ee1a195344ae42f58baf4ca"
182
182
  }
183
183
  ]
184
184
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapsor/runner",
3
- "version": "1.4.12",
3
+ "version": "1.4.122",
4
4
  "description": "Stop giving AI agents execute_sql; expose reviewed Postgres/MySQL MCP actions with proposals, approval, writeback, and replay.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -62,7 +62,10 @@
62
62
  "@modelcontextprotocol/sdk": "1.29.0",
63
63
  "jose": "6.2.3",
64
64
  "mysql2": "^3.11.0",
65
+ "pdf-lib": "1.17.1",
65
66
  "pg": "^8.13.0",
67
+ "vscode-languageserver": "9.0.1",
68
+ "vscode-languageserver-textdocument": "1.0.12",
66
69
  "zod": "^3.25.0"
67
70
  },
68
71
  "devDependencies": {
@@ -70,6 +70,7 @@
70
70
  "required": ["tenant", "allowed_columns", "expected_version"],
71
71
  "properties": {
72
72
  "tenant": { "$ref": "#/$defs/columnValue" },
73
+ "principal_scope": { "$ref": "#/$defs/principalScope" },
73
74
  "allowed_columns": {
74
75
  "type": "array",
75
76
  "items": { "$ref": "#/$defs/safeIdentifier" },
@@ -136,6 +137,19 @@
136
137
  "column": { "$ref": "#/$defs/safeIdentifier" },
137
138
  "value": { "$ref": "#/$defs/scalar" }
138
139
  }
140
+ },
141
+ "principalScope": {
142
+ "type": "object",
143
+ "additionalProperties": false,
144
+ "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"],
145
+ "properties": {
146
+ "schema_version": { "const": "synapsor.principal-scope.v1" },
147
+ "column": { "$ref": "#/$defs/safeIdentifier" },
148
+ "binding": { "$ref": "#/$defs/safeIdentifier" },
149
+ "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] },
150
+ "value_fingerprint": { "type": "string", "pattern": "^sha256:.+" },
151
+ "value": { "$ref": "#/$defs/scalar" }
152
+ }
139
153
  }
140
154
  }
141
155
  }
@@ -80,6 +80,7 @@
80
80
  "required": ["tenant", "allowed_columns"],
81
81
  "properties": {
82
82
  "tenant": { "$ref": "#/$defs/columnValue" },
83
+ "principal_scope": { "$ref": "#/$defs/principalScope" },
83
84
  "allowed_columns": {
84
85
  "type": "array",
85
86
  "items": { "$ref": "#/$defs/safeIdentifier" },
@@ -209,6 +210,19 @@
209
210
  "value": { "$ref": "#/$defs/scalar" }
210
211
  }
211
212
  },
213
+ "principalScope": {
214
+ "type": "object",
215
+ "additionalProperties": false,
216
+ "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"],
217
+ "properties": {
218
+ "schema_version": { "const": "synapsor.principal-scope.v1" },
219
+ "column": { "$ref": "#/$defs/safeIdentifier" },
220
+ "binding": { "$ref": "#/$defs/safeIdentifier" },
221
+ "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] },
222
+ "value_fingerprint": { "$ref": "#/$defs/sha256" },
223
+ "value": { "$ref": "#/$defs/scalar" }
224
+ }
225
+ },
212
226
  "versionAdvance": {
213
227
  "type": "object",
214
228
  "additionalProperties": false,
@@ -37,6 +37,7 @@
37
37
  "type": "object", "additionalProperties": false, "required": ["tenant", "allowed_columns"],
38
38
  "properties": {
39
39
  "tenant": { "$ref": "#/$defs/columnValue" },
40
+ "principal_scope": { "$ref": "#/$defs/principalScope" },
40
41
  "allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/safeIdentifier" }, "maxItems": 256, "uniqueItems": true },
41
42
  "version_advance": { "$ref": "#/$defs/versionAdvance" }
42
43
  }
@@ -96,6 +97,7 @@
96
97
  "scalarRecord": { "type": "object", "propertyNames": { "$ref": "#/$defs/safeIdentifier" }, "additionalProperties": { "$ref": "#/$defs/scalar" }, "maxProperties": 256 },
97
98
  "setOperation": { "enum": ["set_update", "set_delete", "batch_insert"] },
98
99
  "columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/safeIdentifier" }, "value": { "$ref": "#/$defs/scalar" } } },
100
+ "principalScope": { "type": "object", "additionalProperties": false, "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"], "properties": { "schema_version": { "const": "synapsor.principal-scope.v1" }, "column": { "$ref": "#/$defs/safeIdentifier" }, "binding": { "$ref": "#/$defs/safeIdentifier" }, "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] }, "value_fingerprint": { "$ref": "#/$defs/sha256" }, "value": { "$ref": "#/$defs/scalar" } } },
99
101
  "versionAdvance": { "type": "object", "additionalProperties": false, "required": ["column", "strategy"], "properties": { "column": { "$ref": "#/$defs/safeIdentifier" }, "strategy": { "enum": ["integer_increment", "database_generated"] } } },
100
102
  "deduplicationComponent": { "type": "object", "additionalProperties": false, "required": ["column", "value", "source"], "properties": { "column": { "$ref": "#/$defs/safeIdentifier" }, "value": { "$ref": "#/$defs/scalar" }, "source": { "enum": ["proposal_id", "trusted_tenant", "fixed"] } } },
101
103
  "deduplication": { "type": "object", "additionalProperties": false, "required": ["components"], "properties": { "components": { "type": "array", "items": { "$ref": "#/$defs/deduplicationComponent" }, "minItems": 1, "maxItems": 8 } } },
@@ -16,7 +16,7 @@
16
16
  "source": { "type": "object", "additionalProperties": false, "required": ["kind", "source_id", "schema", "table", "primary_key"], "properties": { "kind": { "enum": ["external_postgres", "external_mysql"] }, "source_id": { "type": "string", "minLength": 1 }, "schema": { "$ref": "#/$defs/identifier" }, "table": { "$ref": "#/$defs/identifier" }, "primary_key": { "type": "object", "additionalProperties": false, "required": ["column"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } } } },
17
17
  "before": { "$ref": "#/$defs/record" }, "patch": { "$ref": "#/$defs/record" }, "after": { "$ref": "#/$defs/record" },
18
18
  "compensation": { "type": "object", "additionalProperties": false, "required": ["descriptor", "forward_receipt_hash"], "properties": { "descriptor": { "$ref": "inverse-descriptor.v1.schema.json" }, "forward_receipt_hash": { "$ref": "#/$defs/sha256" } } },
19
- "guards": { "type": "object", "additionalProperties": false, "required": ["tenant", "allowed_columns"], "properties": { "tenant": { "$ref": "#/$defs/columnValue" }, "allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "maxItems": 256, "uniqueItems": true } } },
19
+ "guards": { "type": "object", "additionalProperties": false, "required": ["tenant", "allowed_columns"], "properties": { "tenant": { "$ref": "#/$defs/columnValue" }, "principal_scope": { "$ref": "#/$defs/principalScope" }, "allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "maxItems": 256, "uniqueItems": true } } },
20
20
  "evidence": { "type": "object", "required": ["bundle_id", "query_fingerprint", "items"], "properties": { "bundle_id": { "type": "string", "minLength": 1 }, "query_fingerprint": { "$ref": "#/$defs/sha256" }, "items": { "type": "array", "maxItems": 100 } } },
21
21
  "approval": { "type": "object", "required": ["status", "mode"], "properties": { "status": { "enum": ["pending", "approved", "rejected", "canceled"] }, "mode": { "enum": ["human", "operator"] }, "required_role": { "type": "string", "minLength": 1 }, "required_approvals": { "type": "integer", "minimum": 1, "maximum": 10 } } },
22
22
  "writeback": { "type": "object", "additionalProperties": false, "required": ["status", "mode", "executor"], "properties": { "status": { "const": "not_applied" }, "mode": { "const": "trusted_worker_required" }, "executor": { "const": "sql_update" } } },
@@ -27,6 +27,7 @@
27
27
  "$defs": {
28
28
  "identifier": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "sha256": { "type": "string", "pattern": "^sha256:.+" }, "scalar": { "type": ["string", "number", "boolean", "null"] },
29
29
  "record": { "type": "object", "propertyNames": { "$ref": "#/$defs/identifier" }, "additionalProperties": { "$ref": "#/$defs/scalar" }, "maxProperties": 256 },
30
- "columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } }
30
+ "columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } },
31
+ "principalScope": { "type": "object", "additionalProperties": false, "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"], "properties": { "schema_version": { "const": "synapsor.principal-scope.v1" }, "column": { "$ref": "#/$defs/identifier" }, "binding": { "$ref": "#/$defs/identifier" }, "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] }, "value_fingerprint": { "$ref": "#/$defs/sha256" }, "value": { "$ref": "#/$defs/scalar" } } }
31
32
  }
32
33
  }
@@ -19,6 +19,7 @@
19
19
  "properties": { "source_id": { "type": "string", "minLength": 1 }, "schema": { "$ref": "#/$defs/identifier" }, "table": { "$ref": "#/$defs/identifier" }, "primary_key_column": { "$ref": "#/$defs/identifier" } }
20
20
  },
21
21
  "tenant_guard": { "$ref": "#/$defs/columnValue" },
22
+ "principal_scope": { "$ref": "#/$defs/principalScope" },
22
23
  "allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "maxItems": 256, "uniqueItems": true },
23
24
  "members": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "$ref": "#/$defs/member" } },
24
25
  "max_rows": { "type": "integer", "minimum": 1, "maximum": 100 },
@@ -38,6 +39,7 @@
38
39
  "scalar": { "type": ["string", "number", "boolean", "null"] },
39
40
  "record": { "type": "object", "propertyNames": { "$ref": "#/$defs/identifier" }, "additionalProperties": { "$ref": "#/$defs/scalar" }, "maxProperties": 256 },
40
41
  "columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } },
42
+ "principalScope": { "type": "object", "additionalProperties": false, "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"], "properties": { "schema_version": { "const": "synapsor.principal-scope.v1" }, "column": { "$ref": "#/$defs/identifier" }, "binding": { "$ref": "#/$defs/identifier" }, "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] }, "value_fingerprint": { "type": "string", "pattern": "^sha256:.+" }, "value": { "$ref": "#/$defs/scalar" } } },
41
43
  "member": { "type": "object", "additionalProperties": false, "required": ["primary_key", "expected_state"], "properties": { "primary_key": { "$ref": "#/$defs/columnValue" }, "expected_state": { "$ref": "#/$defs/record" }, "restore_values": { "$ref": "#/$defs/record" } } },
42
44
  "versionAdvance": { "type": "object", "additionalProperties": false, "required": ["column", "strategy"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "strategy": { "enum": ["integer_increment", "database_generated"] } } },
43
45
  "aggregateBound": { "type": "object", "additionalProperties": false, "required": ["column", "measure", "maximum", "actual"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "measure": { "enum": ["before", "after", "absolute_delta"] }, "maximum": { "type": "number", "minimum": 0 }, "actual": { "type": "number", "minimum": 0 } } },
@@ -0,0 +1,54 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.synapsor.ai/synapsor.contract-tests.schema.json",
4
+ "title": "Synapsor adopter contract conformance manifest",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["version", "tests"],
8
+ "properties": {
9
+ "$schema": { "type": "string", "minLength": 1 },
10
+ "version": { "const": 1 },
11
+ "name": { "type": "string", "minLength": 1 },
12
+ "tests": {
13
+ "type": "array",
14
+ "minItems": 1,
15
+ "items": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": ["id", "kind", "capability"],
19
+ "properties": {
20
+ "id": { "type": "string", "minLength": 1 },
21
+ "kind": {
22
+ "enum": ["tool_allow", "tool_deny", "cross_principal_deny", "hide_fields", "argument_constraint", "transition_guard", "set_cap", "source_unchanged_before_approval", "operator_boundary"]
23
+ },
24
+ "capability": { "type": "string", "minLength": 1 },
25
+ "args": { "type": "object" },
26
+ "trusted_context": {
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "required": ["tenant_id", "principal"],
30
+ "properties": {
31
+ "tenant_id": { "type": "string", "minLength": 1 },
32
+ "principal": { "type": "string", "minLength": 1 },
33
+ "provenance": { "enum": ["environment", "static_dev", "http_claims", "cloud_session"] }
34
+ }
35
+ },
36
+ "other_trusted_context": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": ["tenant_id", "principal"],
40
+ "properties": {
41
+ "tenant_id": { "type": "string", "minLength": 1 },
42
+ "principal": { "type": "string", "minLength": 1 },
43
+ "provenance": { "enum": ["environment", "static_dev", "http_claims", "cloud_session"] }
44
+ }
45
+ },
46
+ "expected_code": { "type": "string", "minLength": 1 },
47
+ "fields": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 }, "uniqueItems": true },
48
+ "argument": { "type": "string", "minLength": 1 },
49
+ "expected": { "type": "object" }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }