@synapsor/runner 1.5.3 → 1.6.0

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 (69) hide show
  1. package/CHANGELOG.md +82 -2
  2. package/README.md +131 -130
  3. package/dist/authoring.mjs +405 -9
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/local-ui.d.ts +2 -0
  6. package/dist/local-ui.d.ts.map +1 -1
  7. package/dist/runner.mjs +19532 -14246
  8. package/dist/runtime.mjs +10856 -8495
  9. package/dist/shadow.mjs +101 -1
  10. package/docs/README.md +14 -6
  11. package/docs/aggregate-reads.md +22 -0
  12. package/docs/auto-boundary-and-scoped-explore.md +338 -0
  13. package/docs/capability-authoring.md +36 -1
  14. package/docs/cloud-mode.md +18 -0
  15. package/docs/conformance.md +16 -0
  16. package/docs/current-scope.md +55 -28
  17. package/docs/cursor-plugin.md +20 -3
  18. package/docs/database-enforced-scope.md +8 -0
  19. package/docs/dsl-reference.md +123 -4
  20. package/docs/getting-started-own-database.md +42 -35
  21. package/docs/guarded-crud-writeback.md +10 -1
  22. package/docs/http-mcp.md +222 -207
  23. package/docs/limitations.md +33 -9
  24. package/docs/local-mode.md +5 -2
  25. package/docs/mcp-client-setup.md +24 -11
  26. package/docs/mcp-clients.md +10 -4
  27. package/docs/openai-agents-sdk.md +16 -2
  28. package/docs/production.md +72 -7
  29. package/docs/release-notes.md +77 -3
  30. package/docs/runner-bundles.md +7 -2
  31. package/docs/runner-config-reference.md +96 -6
  32. package/docs/running-a-runner-fleet.md +42 -13
  33. package/docs/schema-api-candidates.md +28 -1
  34. package/docs/security-boundary.md +38 -3
  35. package/docs/store-lifecycle.md +93 -5
  36. package/docs/troubleshooting-first-run.md +98 -0
  37. package/examples/auto-boundary-churn/README.md +23 -0
  38. package/examples/auto-boundary-churn/app/page.tsx +8 -0
  39. package/examples/auto-boundary-churn/docker-compose.yml +16 -0
  40. package/examples/auto-boundary-churn/package.json +18 -0
  41. package/examples/auto-boundary-churn/prisma/schema.prisma +36 -0
  42. package/examples/auto-boundary-churn/seed/postgres.sql +126 -0
  43. package/examples/openai-agents-http/README.md +10 -4
  44. package/examples/openai-agents-http/agent.py +2 -2
  45. package/examples/runner-fleet/Dockerfile +7 -2
  46. package/examples/runner-fleet/README.md +11 -7
  47. package/examples/runner-fleet/docker-compose.yml +4 -4
  48. package/examples/runner-fleet/mint-dev-token.mjs +1 -1
  49. package/examples/runner-fleet/start-tls-runner.sh +21 -0
  50. package/examples/runner-fleet/synapsor.runner.json +27 -1
  51. package/examples/support-plan-credit/README.md +6 -1
  52. package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +4 -1
  53. package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +4 -0
  54. package/examples/support-plan-credit/synapsor.contract.json +0 -3
  55. package/fixtures/compatibility/published-1.5.4/manifest.json +76 -0
  56. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
  57. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
  58. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
  59. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
  60. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
  61. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
  62. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
  63. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
  64. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
  65. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
  66. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
  67. package/llms.txt +37 -0
  68. package/package.json +7 -4
  69. package/schemas/synapsor.runner.schema.json +98 -1
@@ -2,8 +2,11 @@
2
2
 
3
3
  This synthetic fixture starts Postgres, MySQL, and two stateless Streamable
4
4
  HTTP Runner services. Both Runners share one bounded Postgres runtime ledger.
5
- The committed passwords and HS256 key are disposable local-demo values. Never
6
- reuse them outside this fixture.
5
+ Each container generates a one-day self-signed certificate at startup so the
6
+ non-loopback Runner listener exercises direct TLS rather than insecure HTTP.
7
+ The committed database passwords and HS256 key are disposable local-demo
8
+ values. Never reuse them outside this fixture; production should use a trusted
9
+ certificate and asymmetric identity-provider tokens.
7
10
 
8
11
  From the repository root:
9
12
 
@@ -16,9 +19,9 @@ docker compose --profile fleet -f examples/runner-fleet/docker-compose.yml ps
16
19
  Check both instances:
17
20
 
18
21
  ```bash
19
- curl --fail http://127.0.0.1:8871/healthz
20
- curl --fail http://127.0.0.1:8871/readyz
21
- curl --fail http://127.0.0.1:8872/readyz
22
+ curl --fail --insecure https://127.0.0.1:8871/healthz
23
+ curl --fail --insecure https://127.0.0.1:8871/readyz
24
+ curl --fail --insecure https://127.0.0.1:8872/readyz
22
25
  ```
23
26
 
24
27
  The MCP endpoint requires a claim-bearing development JWT. Generate one for
@@ -28,8 +31,9 @@ the fixture only:
28
31
  node examples/runner-fleet/mint-dev-token.mjs acme local-agent
29
32
  ```
30
33
 
31
- The production path should use `jwt_asymmetric` with an explicit RS256/ES256
32
- allowlist and a trusted JWKS URL or public PEM. See
34
+ `--insecure` is acceptable only for this synthetic self-signed fixture. The
35
+ production path should use a trusted TLS chain and `jwt_asymmetric` with an
36
+ explicit RS256/ES256 allowlist plus a trusted JWKS URL or public PEM. See
33
37
  [Running A Runner Fleet](../../docs/running-a-runner-fleet.md).
34
38
 
35
39
  Run the stronger automated verification instead of treating a green Compose
@@ -46,11 +46,11 @@ services:
46
46
  SYNAPSOR_SESSION_JWT_SECRET: synthetic-fleet-session-secret-change-before-use-0001
47
47
  SYNAPSOR_METRICS_TOKEN: synthetic-fleet-metrics-token-change-before-use
48
48
  ports:
49
- - "8871:8766"
49
+ - "127.0.0.1:8871:8766"
50
50
  volumes:
51
51
  - ./synapsor.runner.json:/config/synapsor.runner.json:ro
52
52
  healthcheck:
53
- test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8766/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
53
+ test: ["CMD-SHELL", "NODE_TLS_REJECT_UNAUTHORIZED=0 node -e \"fetch('https://127.0.0.1:8766/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
54
54
  interval: 2s
55
55
  timeout: 5s
56
56
  retries: 30
@@ -66,11 +66,11 @@ services:
66
66
  condition: service_healthy
67
67
  environment: *runner_environment
68
68
  ports:
69
- - "8872:8766"
69
+ - "127.0.0.1:8872:8766"
70
70
  volumes:
71
71
  - ./synapsor.runner.json:/config/synapsor.runner.json:ro
72
72
  healthcheck:
73
- test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8766/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
73
+ test: ["CMD-SHELL", "NODE_TLS_REJECT_UNAUTHORIZED=0 node -e \"fetch('https://127.0.0.1:8766/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
74
74
  interval: 2s
75
75
  timeout: 5s
76
76
  retries: 30
@@ -9,7 +9,7 @@ const payload = {
9
9
  sub: subject,
10
10
  tenant_id: tenant,
11
11
  iss: "https://fleet.example.invalid",
12
- aud: "synapsor-runner-fleet",
12
+ aud: "https://runner-fleet.example.invalid/mcp",
13
13
  iat: now,
14
14
  exp: now + 600,
15
15
  };
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ tls_dir="${SYNAPSOR_FLEET_TLS_DIR:-/tmp/synapsor-runner-tls}"
5
+ mkdir -p "$tls_dir"
6
+ chmod 700 "$tls_dir"
7
+
8
+ openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 1 \
9
+ -subj "/CN=localhost" \
10
+ -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
11
+ -keyout "$tls_dir/server.key" \
12
+ -out "$tls_dir/server.crt" \
13
+ >/dev/null 2>&1
14
+ chmod 600 "$tls_dir/server.key" "$tls_dir/server.crt"
15
+
16
+ export SYNAPSOR_FLEET_TLS_CERT_PEM="$(<"$tls_dir/server.crt")"
17
+ export SYNAPSOR_FLEET_TLS_KEY_PEM="$(<"$tls_dir/server.key")"
18
+
19
+ exec node apps/runner/dist/cli.js "$@" \
20
+ --tls-cert-env SYNAPSOR_FLEET_TLS_CERT_PEM \
21
+ --tls-key-env SYNAPSOR_FLEET_TLS_KEY_PEM
@@ -36,11 +36,37 @@
36
36
  "provider": "jwt_hs256",
37
37
  "secret_env": "SYNAPSOR_SESSION_JWT_SECRET",
38
38
  "issuer": "https://fleet.example.invalid",
39
- "audience": "synapsor-runner-fleet",
39
+ "audience": "https://runner-fleet.example.invalid/mcp",
40
40
  "tenant_claim": "tenant_id",
41
41
  "principal_claim": "sub",
42
42
  "clock_skew_seconds": 10
43
43
  },
44
+ "http_security": {
45
+ "deployment": "shared",
46
+ "oauth_resource": {
47
+ "resource": "https://runner-fleet.example.invalid/mcp",
48
+ "authorization_servers": ["https://fleet.example.invalid"],
49
+ "resource_name": "Synthetic Synapsor Runner fleet"
50
+ },
51
+ "allowed_hosts": [
52
+ "127.0.0.1:8766",
53
+ "127.0.0.1:8871",
54
+ "127.0.0.1:8872",
55
+ "localhost:8766",
56
+ "localhost:8871",
57
+ "localhost:8872"
58
+ ],
59
+ "limits": {
60
+ "max_request_bytes": 65536,
61
+ "max_header_bytes": 8192,
62
+ "max_sessions": 100,
63
+ "session_idle_timeout_seconds": 120,
64
+ "request_timeout_ms": 15000,
65
+ "headers_timeout_ms": 5000,
66
+ "keep_alive_timeout_ms": 5000,
67
+ "max_connections": 200
68
+ }
69
+ },
44
70
  "rate_limits": {
45
71
  "enabled": true,
46
72
  "default": { "requests": 20, "window_seconds": 60 },
@@ -252,13 +252,16 @@ verification gate.
252
252
  For Streamable HTTP, run:
253
253
 
254
254
  ```bash
255
+ export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
256
+
255
257
  synapsor-runner mcp serve \
256
258
  --transport streamable-http \
257
259
  --alias-mode openai \
258
260
  --host 127.0.0.1 \
259
261
  --port 8766 \
260
262
  --config examples/support-plan-credit/synapsor.runner.json \
261
- --store ./tmp/support-plan-credit/local.db
263
+ --store ./tmp/support-plan-credit/local.db \
264
+ --auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
262
265
  ```
263
266
 
264
267
  The OpenAI client receives `support__inspect_customer` and
@@ -266,6 +269,8 @@ The OpenAI client receives `support__inspect_customer` and
266
269
  tool metadata and results. For Claude, Cursor, or generic MCP clients, omit
267
270
  `--alias-mode openai` to expose `support.inspect_customer` and
268
271
  `support.propose_plan_credit`. Approval and apply remain outside MCP.
272
+ The HTTP client reads the same opaque endpoint token from its protected
273
+ environment; no token value belongs in the checked-in recipe.
269
274
 
270
275
  ## How The Policy Is Governed
271
276
 
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "name": "synapsor-runner",
3
3
  "transport": "streamable-http",
4
- "url": "http://127.0.0.1:8766/mcp"
4
+ "url": "http://127.0.0.1:8766/mcp",
5
+ "headers_from_env": {
6
+ "Authorization": "Bearer $SYNAPSOR_RUNNER_HTTP_TOKEN"
7
+ }
5
8
  }
@@ -1,9 +1,13 @@
1
1
  import { Agent, MCPServerStreamableHttp, run } from "@openai/agents";
2
2
 
3
3
  // Start Runner with --alias-mode openai so model-visible tool names are valid OpenAI function names.
4
+ const token = process.env.SYNAPSOR_RUNNER_HTTP_TOKEN;
5
+ if (!token) throw new Error("set SYNAPSOR_RUNNER_HTTP_TOKEN in the launching environment");
6
+
4
7
  const synapsor = new MCPServerStreamableHttp({
5
8
  name: "Synapsor Runner",
6
9
  url: "http://127.0.0.1:8766/mcp",
10
+ requestInit: { headers: { Authorization: `Bearer ${token}` } },
7
11
  });
8
12
 
9
13
  await synapsor.connect();
@@ -182,9 +182,6 @@
182
182
  "mode": "human",
183
183
  "required_role": "support_reviewer"
184
184
  },
185
- "conflict_guard": {
186
- "weak_guard_ack": true
187
- },
188
185
  "numeric_bounds": {
189
186
  "amount_cents": {
190
187
  "maximum": 50000,
@@ -0,0 +1,76 @@
1
+ {
2
+ "schema_version": "synapsor.published-compatibility.v1",
3
+ "published_packages": {
4
+ "@synapsor/runner": {
5
+ "version": "1.5.4",
6
+ "npm_shasum": "63ef030b0360118082bc670239ad4927673b6bc7"
7
+ },
8
+ "@synapsor/dsl": {
9
+ "version": "1.4.4",
10
+ "npm_shasum": "dee671d3c3d25f5434b488f80b3041d0c5606c2f"
11
+ },
12
+ "@synapsor/spec": {
13
+ "version": "1.4.2",
14
+ "npm_shasum": "cb9aa813f481ef14d542a1896c228159aab86353"
15
+ }
16
+ },
17
+ "contracts": [
18
+ {
19
+ "path": "packages/spec/fixtures/valid/basic-read.contract.json",
20
+ "source_sha256": "5ec499965f639d784603b7942390d18a3e742d79e4d510dbea470e166a743972",
21
+ "canonical_sha256": "9d3addfde77eb6528aae7b9e81ae0f582b5c002aa77ebb2d7381fe663f5f5b1e"
22
+ },
23
+ {
24
+ "path": "packages/spec/fixtures/conformance/aggregate-read/contract.json",
25
+ "source_sha256": "830bc208b749bb9ed6a4b4468571d58d68bc8a2b6e1072fc45fb87d1c68697e7",
26
+ "canonical_sha256": "ccc6ea17f449bfc207d1cea70ef3320d575c450a3904c850dcb631132c6e5602"
27
+ },
28
+ {
29
+ "path": "packages/spec/fixtures/conformance/proposal-capability/contract.json",
30
+ "source_sha256": "d4c25fb8f79f04c13bdb3daf8c18a44d4f1c61596660a67bf35d46d0f94f4100",
31
+ "canonical_sha256": "d895081246d41a072892b5dde6929099302492a77a229033fbfa5052cce34b18"
32
+ },
33
+ {
34
+ "path": "packages/spec/fixtures/conformance/bounded-set-threats/contract.json",
35
+ "source_sha256": "c902d45457789a6d87504ca434c8b299f3e09be779f3bfdf7bbd8684d575a10e",
36
+ "canonical_sha256": "64c7078ff1687762d95c17873238759b3572dce499f903a8d6f1aaa8faae5f24"
37
+ },
38
+ {
39
+ "path": "packages/spec/fixtures/conformance/reversible-change-sets/contract.json",
40
+ "source_sha256": "7e4f8da90a4b235097f76e70a7f550153bbf62d219e7ef6f4f2194f6c36fa205",
41
+ "canonical_sha256": "181f2e93ad3c53b9a1345a4ed6c8b5e24ab0201c00159f38659f0c2a00c037de"
42
+ },
43
+ {
44
+ "path": "packages/spec/fixtures/conformance/principal-row-scope/contract.json",
45
+ "source_sha256": "00a05c1f4e82cc9c4e5d2d68c9c9201cd9512ac42d63292314bb7b4845026996",
46
+ "canonical_sha256": "fc96a5327ab0f4b311c90da9b5585348e81349ed66bd3a22e41e5f29804c32a8"
47
+ },
48
+ {
49
+ "path": "packages/spec/fixtures/conformance/approval-quorum/contract.json",
50
+ "source_sha256": "dde6b328f648ba60d837fa363494d764d7eb0d2d9a8a81ff70a9c077edde410c",
51
+ "canonical_sha256": "9407a7d0cc4439c773c3caf721aaed6c6e163c403fa67518632829d8c5de33e7"
52
+ }
53
+ ],
54
+ "dsl_sources": [
55
+ {
56
+ "path": "packages/dsl/examples/aggregate-read.synapsor.sql",
57
+ "source_sha256": "bccac4c2eb0ab7b2fc099c7fb3f6fdc25ee2e6e534282aa19b46f0aec8191b8d",
58
+ "canonical_sha256": "0cc2d892f00a31a3582d773812a26c6c45c0ce343e1d8d09da226a5bbb7c93eb"
59
+ },
60
+ {
61
+ "path": "packages/dsl/examples/billing-late-fee.synapsor.sql",
62
+ "source_sha256": "f5c462cff7aa0cd01a08543c6096ee1d225ebba449d65b7470815b1aa7ec42cd",
63
+ "canonical_sha256": "d495df575d64e798a730dad385e097dfc2c2f371a1505865bc45179ad3c479f2"
64
+ },
65
+ {
66
+ "path": "packages/dsl/examples/bounded-set-multi-term.synapsor.sql",
67
+ "source_sha256": "0ae199034ebba8b25146435c911576118f948b55b54636a5e68f46002cd1c6dd",
68
+ "canonical_sha256": "5b3e84cf8f5062a8afcd50763bde907e6a141977456e74a81d01f8b3a484e422"
69
+ },
70
+ {
71
+ "path": "packages/dsl/examples/principal-row-scope.synapsor.sql",
72
+ "source_sha256": "08ccd769d633417ea45d478383d9628991f43262223f12c78bbd776202b10253",
73
+ "canonical_sha256": "e29f2819c267210e54f783c40d0f550d11d0d1de844dbe1590ed8c3405af3cf7"
74
+ }
75
+ ]
76
+ }
@@ -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,56 @@
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 billing.inspect_invoice
9
+ DESCRIPTION 'Inspect one invoice in the trusted tenant before proposing a waiver.'
10
+ RETURNS HINT 'Returns reviewed invoice fields plus evidence/query-audit handles.'
11
+ USING CONTEXT local_operator
12
+ SOURCE local_postgres
13
+ ON public.invoices
14
+ PRIMARY KEY id
15
+ TENANT KEY tenant_id
16
+ CONFLICT GUARD updated_at
17
+ LOOKUP invoice_id BY id
18
+ ARG invoice_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Invoice id such as INV-3001.'
19
+ ALLOW READ id, tenant_id, customer_id, status, late_fee_cents, waiver_reason, updated_at
20
+ KEEP OUT card_token, internal_risk_score
21
+ REQUIRE EVIDENCE
22
+ MAX ROWS 1
23
+ END
24
+
25
+ CREATE CAPABILITY billing.propose_late_fee_waiver
26
+ DESCRIPTION 'Propose waiving one invoice late fee after inspecting invoice and policy evidence.'
27
+ RETURNS HINT 'Returns a review-required proposal id, exact diff, evidence handle, and source_database_changed:false.'
28
+ USING CONTEXT local_operator
29
+ SOURCE local_postgres
30
+ ON public.invoices
31
+ PRIMARY KEY id
32
+ TENANT KEY tenant_id
33
+ CONFLICT GUARD updated_at
34
+ LOOKUP invoice_id BY id
35
+ ARG invoice_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Invoice id such as INV-3001.'
36
+ ARG waiver_reason TEXT REQUIRED MAX LENGTH 500 DESCRIPTION 'Business reason for the proposed waiver.'
37
+ ALLOW READ id, tenant_id, customer_id, status, late_fee_cents, waiver_reason, updated_at
38
+ KEEP OUT card_token, internal_risk_score
39
+ REQUIRE EVIDENCE
40
+ MAX ROWS 1
41
+ PROPOSE ACTION billing.waive_late_fee
42
+ ALLOW WRITE late_fee_cents, waiver_reason
43
+ PATCH late_fee_cents = 0
44
+ PATCH waiver_reason = ARG waiver_reason
45
+ APPROVAL ROLE billing_lead
46
+ WRITEBACK DIRECT SQL
47
+ END
48
+
49
+ CREATE AGENT WORKFLOW billing.late_fee_review
50
+ USING CONTEXT local_operator
51
+ ALLOW CAPABILITY billing.inspect_invoice
52
+ ALLOW CAPABILITY billing.propose_late_fee_waiver
53
+ REQUIRE EVIDENCE
54
+ APPROVAL REQUIRED ROLE billing_lead
55
+ CHECKPOINT PROPOSAL ONLY
56
+ 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
@@ -0,0 +1,119 @@
1
+ {
2
+ "spec_version": "0.1",
3
+ "kind": "SynapsorContract",
4
+ "metadata": {
5
+ "name": "aggregate read and enum conformance",
6
+ "version": "1.0.0"
7
+ },
8
+ "resources": [
9
+ {
10
+ "name": "billing_invoices",
11
+ "engine": "postgres",
12
+ "schema": "public",
13
+ "table": "invoices",
14
+ "primary_key": "id",
15
+ "tenant_key": "tenant_id"
16
+ }
17
+ ],
18
+ "contexts": [
19
+ {
20
+ "name": "billing_context",
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": "billing.sum_overdue_balance",
40
+ "description": "Return one privacy-suppressed aggregate for the trusted tenant.",
41
+ "returns_hint": "Returns one scalar or a suppression result; never member rows.",
42
+ "kind": "aggregate_read",
43
+ "context": "billing_context",
44
+ "source": "local_postgres",
45
+ "subject": {
46
+ "resource": "billing_invoices"
47
+ },
48
+ "args": {},
49
+ "visible_fields": [],
50
+ "kept_out_fields": [
51
+ "customer_email",
52
+ "private_notes"
53
+ ],
54
+ "evidence": {
55
+ "required": true,
56
+ "query_audit": true
57
+ },
58
+ "aggregate": {
59
+ "function": "sum",
60
+ "column": "balance_cents",
61
+ "selection": {
62
+ "all": [
63
+ {
64
+ "column": "status",
65
+ "operator": "eq",
66
+ "value": "overdue"
67
+ }
68
+ ]
69
+ },
70
+ "minimum_group_size": 5
71
+ }
72
+ },
73
+ {
74
+ "name": "billing.inspect_invoice",
75
+ "description": "Inspect one tenant-scoped invoice using a reviewed risk enum.",
76
+ "kind": "read",
77
+ "context": "billing_context",
78
+ "source": "local_postgres",
79
+ "subject": {
80
+ "resource": "billing_invoices"
81
+ },
82
+ "args": {
83
+ "invoice_id": {
84
+ "type": "string",
85
+ "required": true,
86
+ "max_length": 128
87
+ },
88
+ "risk_level": {
89
+ "type": "string",
90
+ "required": true,
91
+ "enum": [
92
+ "low",
93
+ "medium",
94
+ "high"
95
+ ]
96
+ }
97
+ },
98
+ "lookup": {
99
+ "id_from_arg": "invoice_id"
100
+ },
101
+ "visible_fields": [
102
+ "id",
103
+ "tenant_id",
104
+ "status",
105
+ "balance_cents"
106
+ ],
107
+ "kept_out_fields": [
108
+ "customer_email",
109
+ "private_notes"
110
+ ],
111
+ "evidence": {
112
+ "required": true,
113
+ "query_audit": true
114
+ },
115
+ "max_rows": 1
116
+ }
117
+ ]
118
+ }
119
+
@@ -0,0 +1,44 @@
1
+ {
2
+ "spec_version": "0.1",
3
+ "kind": "SynapsorContract",
4
+ "contexts": [
5
+ {
6
+ "name": "local_operator",
7
+ "bindings": [
8
+ { "name": "tenant_id", "source": "environment", "key": "SYNAPSOR_TENANT_ID" },
9
+ { "name": "principal", "source": "environment", "key": "SYNAPSOR_PRINCIPAL" }
10
+ ],
11
+ "tenant_binding": "tenant_id",
12
+ "principal_binding": "principal"
13
+ }
14
+ ],
15
+ "capabilities": [
16
+ {
17
+ "name": "billing.propose_late_fee_waiver",
18
+ "kind": "proposal",
19
+ "context": "local_operator",
20
+ "subject": {
21
+ "schema": "public",
22
+ "table": "invoices",
23
+ "primary_key": "id",
24
+ "tenant_key": "tenant_id",
25
+ "conflict_key": "updated_at"
26
+ },
27
+ "args": { "invoice_id": { "type": "string" } },
28
+ "lookup": { "id_from_arg": "invoice_id" },
29
+ "visible_fields": ["id", "tenant_id", "late_fee_cents", "updated_at"],
30
+ "proposal": {
31
+ "action": "billing.waive_late_fee",
32
+ "allowed_fields": ["late_fee_cents"],
33
+ "patch": { "late_fee_cents": { "fixed": 0 } },
34
+ "conflict_guard": { "column": "updated_at" },
35
+ "approval": {
36
+ "mode": "human",
37
+ "required_role": "billing_lead",
38
+ "required_approvals": 2
39
+ },
40
+ "writeback": { "mode": "direct_sql" }
41
+ }
42
+ }
43
+ ]
44
+ }