@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.
- package/CHANGELOG.md +82 -2
- package/README.md +131 -130
- package/dist/authoring.mjs +405 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +2 -0
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +19532 -14246
- package/dist/runtime.mjs +10856 -8495
- package/dist/shadow.mjs +101 -1
- package/docs/README.md +14 -6
- package/docs/aggregate-reads.md +22 -0
- package/docs/auto-boundary-and-scoped-explore.md +338 -0
- package/docs/capability-authoring.md +36 -1
- package/docs/cloud-mode.md +18 -0
- package/docs/conformance.md +16 -0
- package/docs/current-scope.md +55 -28
- package/docs/cursor-plugin.md +20 -3
- package/docs/database-enforced-scope.md +8 -0
- package/docs/dsl-reference.md +123 -4
- package/docs/getting-started-own-database.md +42 -35
- package/docs/guarded-crud-writeback.md +10 -1
- package/docs/http-mcp.md +222 -207
- package/docs/limitations.md +33 -9
- package/docs/local-mode.md +5 -2
- package/docs/mcp-client-setup.md +24 -11
- package/docs/mcp-clients.md +10 -4
- package/docs/openai-agents-sdk.md +16 -2
- package/docs/production.md +72 -7
- package/docs/release-notes.md +77 -3
- package/docs/runner-bundles.md +7 -2
- package/docs/runner-config-reference.md +96 -6
- package/docs/running-a-runner-fleet.md +42 -13
- package/docs/schema-api-candidates.md +28 -1
- package/docs/security-boundary.md +38 -3
- package/docs/store-lifecycle.md +93 -5
- package/docs/troubleshooting-first-run.md +98 -0
- package/examples/auto-boundary-churn/README.md +23 -0
- package/examples/auto-boundary-churn/app/page.tsx +8 -0
- package/examples/auto-boundary-churn/docker-compose.yml +16 -0
- package/examples/auto-boundary-churn/package.json +18 -0
- package/examples/auto-boundary-churn/prisma/schema.prisma +36 -0
- package/examples/auto-boundary-churn/seed/postgres.sql +126 -0
- package/examples/openai-agents-http/README.md +10 -4
- package/examples/openai-agents-http/agent.py +2 -2
- package/examples/runner-fleet/Dockerfile +7 -2
- package/examples/runner-fleet/README.md +11 -7
- package/examples/runner-fleet/docker-compose.yml +4 -4
- package/examples/runner-fleet/mint-dev-token.mjs +1 -1
- package/examples/runner-fleet/start-tls-runner.sh +21 -0
- package/examples/runner-fleet/synapsor.runner.json +27 -1
- package/examples/support-plan-credit/README.md +6 -1
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +4 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +4 -0
- package/examples/support-plan-credit/synapsor.contract.json +0 -3
- package/fixtures/compatibility/published-1.5.4/manifest.json +76 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/llms.txt +37 -0
- package/package.json +7 -4
- 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
|
-
|
|
6
|
-
|
|
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
|
|
20
|
-
curl --fail
|
|
21
|
-
curl --fail
|
|
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
|
-
|
|
32
|
-
|
|
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
|
|
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
|
|
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
|
|
@@ -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": "
|
|
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,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();
|
|
@@ -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
|
+
}
|