@synapsor/runner 1.6.0 → 1.6.1
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 +32 -4
- package/README.md +16 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +4 -1
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +1624 -42
- package/dist/runtime.mjs +1011 -25
- package/dist/shadow.mjs +408 -15
- package/docs/app-owned-executors.md +8 -0
- package/docs/capability-authoring.md +45 -0
- package/docs/current-scope.md +5 -0
- package/docs/cursor-plugin.md +2 -2
- package/docs/limitations.md +15 -2
- package/docs/local-mode.md +22 -3
- package/docs/production.md +19 -0
- package/docs/proposal-evidence-freshness.md +334 -0
- package/docs/release-notes.md +30 -4
- package/docs/runner-config-reference.md +46 -0
- package/docs/security-boundary.md +17 -0
- package/docs/store-lifecycle.md +8 -0
- package/docs/troubleshooting-first-run.md +76 -0
- package/docs/writeback-executors.md +8 -0
- package/examples/app-owned-writeback/command-handler.mjs +0 -0
- package/examples/mcp-postgres-billing-app-handler/scripts/run-demo.sh +0 -0
- package/examples/reference-support-billing-app/scripts/run-demo.sh +0 -0
- package/examples/support-billing-agent/scripts/run-demo.sh +0 -0
- package/examples/support-billing-agent/scripts/run-evaluation.sh +0 -0
- package/fixtures/compatibility/published-1.6.0/manifest.json +76 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/fixtures/protocol/MANIFEST.json +37 -7
- package/fixtures/protocol/change-set.freshness-update.v2.json +58 -0
- package/fixtures/protocol/freshness-authority.invoice.v1.json +35 -0
- package/fixtures/protocol/freshness-proof.fresh.v1.json +38 -0
- package/fixtures/protocol/writeback-job.freshness-update.v2.json +50 -0
- package/llms.txt +1 -0
- package/package.json +9 -8
- package/schemas/change-set.v1.schema.json +1 -0
- package/schemas/change-set.v2.schema.json +1 -0
- package/schemas/change-set.v3.schema.json +1 -0
- package/schemas/freshness-authority.v1.schema.json +89 -0
- package/schemas/freshness-proof.v1.schema.json +73 -0
- package/schemas/synapsor.runner.schema.json +32 -0
- package/schemas/writeback-job.v1.schema.json +1 -0
- package/schemas/writeback-job.v2.schema.json +1 -0
- package/schemas/writeback-job.v3.schema.json +1 -0
|
@@ -120,6 +120,16 @@ explicit host-level administrative boundary.
|
|
|
120
120
|
Proposal tools read the current row through the read credential, store evidence
|
|
121
121
|
and an exact before/after diff, and leave the source database unchanged.
|
|
122
122
|
|
|
123
|
+
For an explicitly freshness-enabled proposal, Runner also captures exact
|
|
124
|
+
version authority for the target and reviewed same-source supporting rows.
|
|
125
|
+
Before each local approval it performs a read-only live check and binds the
|
|
126
|
+
successful proof to that approval. This improves review integrity but does not
|
|
127
|
+
hold a lock through apply. The trusted direct SQL apply path therefore locks
|
|
128
|
+
and rechecks the dependencies again inside the mutation transaction. A stale
|
|
129
|
+
or unverifiable dependency produces no mutation and is never silently
|
|
130
|
+
refreshed. See
|
|
131
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
132
|
+
|
|
123
133
|
Code-first Safe Actions do not create authority when a file is edited. Runner
|
|
124
134
|
parses the restricted TypeScript object without importing or executing it,
|
|
125
135
|
compiles it into a digest-addressed disabled canonical draft, and keeps the
|
|
@@ -153,11 +163,18 @@ outside the model-facing MCP server and verifies:
|
|
|
153
163
|
- conflict/version guard;
|
|
154
164
|
- idempotency key;
|
|
155
165
|
- operation-specific version or source-unique deduplication guard;
|
|
166
|
+
- declared same-source supporting-version guards, when freshness is required;
|
|
156
167
|
- job expiry;
|
|
157
168
|
- exactly one reviewed row or every member of one bounded frozen set.
|
|
158
169
|
|
|
159
170
|
If any authority check cannot be verified, the write fails closed.
|
|
160
171
|
|
|
172
|
+
Strict freshness is intentionally limited to same-database direct SQL
|
|
173
|
+
writeback. Runner rejects app-owned or cross-source strict freshness because it
|
|
174
|
+
cannot claim one atomic transaction around those effects. Cloud can govern an
|
|
175
|
+
approval, but it does not read the source; the local Runner revalidates source
|
|
176
|
+
state before a Cloud-approved job can mutate data.
|
|
177
|
+
|
|
161
178
|
For direct SQL writeback, the writer connection is the env var named by the
|
|
162
179
|
source `write_url_env` in `synapsor.runner.json`. With `source_db` receipt
|
|
163
180
|
authority, the source mutation and receipt commit atomically; the receipt table
|
package/docs/store-lifecycle.md
CHANGED
|
@@ -48,6 +48,7 @@ then proposal id as the tie-breaker. The default view answers:
|
|
|
48
48
|
- what capability and business object the model requested;
|
|
49
49
|
- which trusted tenant and principal scoped it;
|
|
50
50
|
- approval state and progress;
|
|
51
|
+
- required/live freshness state and the proof digest bound to each approval;
|
|
51
52
|
- whether a writeback job or intent exists;
|
|
52
53
|
- the latest guarded outcome and whether the source changed;
|
|
53
54
|
- replay and Cloud-link status; and
|
|
@@ -123,6 +124,7 @@ The existing commands remain useful when you need one record type:
|
|
|
123
124
|
| Question | Focused command |
|
|
124
125
|
| --- | --- |
|
|
125
126
|
| What did the model propose? | `synapsor-runner proposals show latest --details` |
|
|
127
|
+
| Is the latest proposal still fresh enough to review? | `synapsor-runner proposals check-freshness latest --config ./synapsor.runner.json` |
|
|
126
128
|
| What data supported it? | `synapsor-runner evidence list --proposal <proposal-id>` then `evidence show <evidence-id> --details` |
|
|
127
129
|
| What query was run? | `synapsor-runner query-audit list --proposal <proposal-id>` |
|
|
128
130
|
| Did guarded writeback apply? | `synapsor-runner receipts list --proposal <proposal-id>` |
|
|
@@ -135,6 +137,12 @@ The existing commands remain useful when you need one record type:
|
|
|
135
137
|
it materializes a job and is therefore an operator mutation, not a read-only
|
|
136
138
|
view.
|
|
137
139
|
|
|
140
|
+
`proposals check-freshness` is source-read-only but is not a ledger-pure
|
|
141
|
+
inspection: it contacts the configured source and records an immutable proof
|
|
142
|
+
event. The `lifecycle` command never does that; it only reports the most recent
|
|
143
|
+
stored proof and approval linkage. See
|
|
144
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
145
|
+
|
|
138
146
|
## Server leases
|
|
139
147
|
|
|
140
148
|
MCP server modes write a small lease file next to the store:
|
|
@@ -364,6 +364,82 @@ Fix:
|
|
|
364
364
|
Use a read-only credential for MCP reads and a separate writer credential only
|
|
365
365
|
for trusted apply.
|
|
366
366
|
|
|
367
|
+
## Freshness Check Is Stale
|
|
368
|
+
|
|
369
|
+
What happened:
|
|
370
|
+
|
|
371
|
+
```text
|
|
372
|
+
Freshness: stale
|
|
373
|
+
code: FRESHNESS_TARGET_STALE
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
or:
|
|
377
|
+
|
|
378
|
+
```text
|
|
379
|
+
code: FRESHNESS_DEPENDENCY_STALE
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Why it matters:
|
|
383
|
+
|
|
384
|
+
The proposal target or one explicitly declared supporting row no longer has
|
|
385
|
+
the exact version captured by the immutable proposal. Runner records no
|
|
386
|
+
approval and never updates the old proposal to match current data.
|
|
387
|
+
|
|
388
|
+
Fix:
|
|
389
|
+
|
|
390
|
+
Perform a new reviewed source read and create a new proposal. Do not retry
|
|
391
|
+
approval on the stale proposal or edit its stored JSON.
|
|
392
|
+
|
|
393
|
+
## Freshness Check Is Unavailable
|
|
394
|
+
|
|
395
|
+
What happened:
|
|
396
|
+
|
|
397
|
+
```text
|
|
398
|
+
Freshness: unavailable
|
|
399
|
+
code: FRESHNESS_TEMPORARILY_UNAVAILABLE
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Why it matters:
|
|
403
|
+
|
|
404
|
+
Runner could not prove current source state. Unavailability is not treated as
|
|
405
|
+
fresh, and no approval was recorded.
|
|
406
|
+
|
|
407
|
+
Fix:
|
|
408
|
+
|
|
409
|
+
Restore the read connection or resolve the transient database/pool issue, then
|
|
410
|
+
retry:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
synapsor-runner proposals check-freshness latest \
|
|
414
|
+
--config ./synapsor.runner.json \
|
|
415
|
+
--store ./.synapsor/local.db
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## Freshness Writer Lock Probe Failed
|
|
419
|
+
|
|
420
|
+
What happened:
|
|
421
|
+
|
|
422
|
+
`doctor --check-writeback` reports that the writer cannot lock a declared
|
|
423
|
+
supporting dependency.
|
|
424
|
+
|
|
425
|
+
Why it matters:
|
|
426
|
+
|
|
427
|
+
Approval-time reads alone cannot provide the final atomic guarantee. The direct
|
|
428
|
+
SQL adapter must lock and compare every dependency inside the mutation
|
|
429
|
+
transaction.
|
|
430
|
+
|
|
431
|
+
Fix:
|
|
432
|
+
|
|
433
|
+
Grant only the narrow table/column privilege required for the writer's
|
|
434
|
+
`SELECT ... FOR UPDATE` locking read, then rerun:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
synapsor-runner doctor --check-writeback --config ./synapsor.runner.json
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Do not replace this with an overprivileged owner/superuser role. See
|
|
441
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
442
|
+
|
|
367
443
|
## MCP Client Config Contains A Secret
|
|
368
444
|
|
|
369
445
|
What happened:
|
|
@@ -250,3 +250,11 @@ Executor secrets are never exposed over MCP. The model never receives:
|
|
|
250
250
|
|
|
251
251
|
`MCP tool call = request/proposal authority. Trusted runner = execution
|
|
252
252
|
authority.`
|
|
253
|
+
|
|
254
|
+
Optional Runner `proposal_freshness` adds pre-approval and final-transaction
|
|
255
|
+
checks only to same-source direct SQL writeback. It is deliberately rejected
|
|
256
|
+
for HTTP/command handlers and cross-source dependencies: Runner cannot claim an
|
|
257
|
+
atomic source check around an externally owned transaction. Handler authors
|
|
258
|
+
must implement equivalent scope, exact-version, locking, idempotency, and
|
|
259
|
+
receipt semantics themselves. See
|
|
260
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "synapsor.published-compatibility.v1",
|
|
3
|
+
"published_packages": {
|
|
4
|
+
"@synapsor/runner": {
|
|
5
|
+
"version": "1.6.0",
|
|
6
|
+
"npm_shasum": "3ac934e1742184514c7eca935d7d3c1ca752bb70"
|
|
7
|
+
},
|
|
8
|
+
"@synapsor/dsl": {
|
|
9
|
+
"version": "1.5.0",
|
|
10
|
+
"npm_shasum": "45832b2e4e754bd68d195e3daf14b1c14edbc27d"
|
|
11
|
+
},
|
|
12
|
+
"@synapsor/spec": {
|
|
13
|
+
"version": "1.5.0",
|
|
14
|
+
"npm_shasum": "e167ccff21e0a511bbe0758d0a918fdd59b03b4d"
|
|
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
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
{
|
|
2
|
+
"spec_version": "0.1",
|
|
3
|
+
"kind": "SynapsorContract",
|
|
4
|
+
"metadata": { "name": "bounded-set-threats", "version": "1.0.0" },
|
|
5
|
+
"contexts": [
|
|
6
|
+
{
|
|
7
|
+
"name": "trusted_operator",
|
|
8
|
+
"bindings": [
|
|
9
|
+
{ "name": "tenant_id", "source": "environment", "key": "SYNAPSOR_TENANT_ID", "required": true },
|
|
10
|
+
{ "name": "principal", "source": "environment", "key": "SYNAPSOR_PRINCIPAL", "required": true }
|
|
11
|
+
],
|
|
12
|
+
"tenant_binding": "tenant_id",
|
|
13
|
+
"principal_binding": "principal"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"capabilities": [
|
|
17
|
+
{
|
|
18
|
+
"name": "billing.close_overdue_invoices",
|
|
19
|
+
"kind": "proposal",
|
|
20
|
+
"context": "trusted_operator",
|
|
21
|
+
"source": "local_postgres",
|
|
22
|
+
"subject": { "schema": "public", "table": "invoices", "primary_key": "id", "tenant_key": "tenant_id", "conflict_key": "version" },
|
|
23
|
+
"args": { "reason": { "type": "string", "required": true, "max_length": 500 } },
|
|
24
|
+
"visible_fields": ["id", "tenant_id", "status", "balance_cents", "version"],
|
|
25
|
+
"kept_out_fields": ["internal_risk_score"],
|
|
26
|
+
"evidence": { "required": true, "query_audit": true },
|
|
27
|
+
"proposal": {
|
|
28
|
+
"action": "close_overdue",
|
|
29
|
+
"operation": {
|
|
30
|
+
"kind": "update",
|
|
31
|
+
"cardinality": "set",
|
|
32
|
+
"selection": { "all": [{ "column": "status", "operator": "eq", "value": "overdue" }] },
|
|
33
|
+
"max_rows": 10,
|
|
34
|
+
"aggregate_bounds": [{ "column": "balance_cents", "measure": "before", "maximum": 50000 }],
|
|
35
|
+
"version_advance": { "column": "version", "strategy": "integer_increment" }
|
|
36
|
+
},
|
|
37
|
+
"allowed_fields": ["status", "close_reason"],
|
|
38
|
+
"patch": { "status": { "fixed": "closed" }, "close_reason": { "from_arg": "reason" } },
|
|
39
|
+
"conflict_guard": { "column": "version" },
|
|
40
|
+
"approval": { "mode": "human", "required_role": "billing_reviewer" },
|
|
41
|
+
"writeback": { "mode": "direct_sql" }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "billing.delete_expired_drafts",
|
|
46
|
+
"kind": "proposal",
|
|
47
|
+
"context": "trusted_operator",
|
|
48
|
+
"source": "local_postgres",
|
|
49
|
+
"subject": { "schema": "public", "table": "invoice_drafts", "primary_key": "id", "tenant_key": "tenant_id", "conflict_key": "version" },
|
|
50
|
+
"args": { "reason": { "type": "string", "required": true, "max_length": 500 } },
|
|
51
|
+
"visible_fields": ["id", "tenant_id", "status", "estimated_cents", "version"],
|
|
52
|
+
"evidence": { "required": true, "query_audit": true },
|
|
53
|
+
"proposal": {
|
|
54
|
+
"action": "delete_expired_drafts",
|
|
55
|
+
"operation": {
|
|
56
|
+
"kind": "delete",
|
|
57
|
+
"cardinality": "set",
|
|
58
|
+
"selection": { "all": [{ "column": "status", "operator": "eq", "value": "expired" }] },
|
|
59
|
+
"max_rows": 5,
|
|
60
|
+
"aggregate_bounds": [{ "column": "estimated_cents", "measure": "before", "maximum": 10000 }]
|
|
61
|
+
},
|
|
62
|
+
"allowed_fields": [],
|
|
63
|
+
"patch": {},
|
|
64
|
+
"conflict_guard": { "column": "version" },
|
|
65
|
+
"approval": { "mode": "human", "required_role": "billing_reviewer", "required_approvals": 2 },
|
|
66
|
+
"writeback": { "mode": "direct_sql" }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "billing.create_credits",
|
|
71
|
+
"kind": "proposal",
|
|
72
|
+
"context": "trusted_operator",
|
|
73
|
+
"source": "local_postgres",
|
|
74
|
+
"subject": { "schema": "public", "table": "account_credits", "primary_key": "id", "tenant_key": "tenant_id" },
|
|
75
|
+
"args": {
|
|
76
|
+
"items": {
|
|
77
|
+
"type": "object_array",
|
|
78
|
+
"required": true,
|
|
79
|
+
"max_items": 10,
|
|
80
|
+
"fields": {
|
|
81
|
+
"id": { "type": "string", "required": true, "max_length": 128 },
|
|
82
|
+
"external_id": { "type": "string", "required": true, "max_length": 128 },
|
|
83
|
+
"amount_cents": { "type": "number", "required": true, "minimum": 1, "maximum": 2500 },
|
|
84
|
+
"reason": { "type": "string", "required": true, "max_length": 500 }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"visible_fields": ["id", "tenant_id", "external_id", "amount_cents", "reason", "version"],
|
|
89
|
+
"kept_out_fields": ["internal_note"],
|
|
90
|
+
"evidence": { "required": true, "query_audit": true },
|
|
91
|
+
"proposal": {
|
|
92
|
+
"action": "create_credits",
|
|
93
|
+
"operation": {
|
|
94
|
+
"kind": "insert",
|
|
95
|
+
"cardinality": "set",
|
|
96
|
+
"batch": { "items_from_arg": "items" },
|
|
97
|
+
"max_rows": 10,
|
|
98
|
+
"aggregate_bounds": [{ "column": "amount_cents", "measure": "after", "maximum": 25000 }],
|
|
99
|
+
"deduplication": {
|
|
100
|
+
"components": [
|
|
101
|
+
{ "column": "tenant_id", "source": "trusted_tenant" },
|
|
102
|
+
{ "column": "id", "source": "item_field", "item_field": "id" },
|
|
103
|
+
{ "column": "external_id", "source": "item_field", "item_field": "external_id" }
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"allowed_fields": ["amount_cents", "reason"],
|
|
108
|
+
"patch": { "amount_cents": { "from_item": "amount_cents" }, "reason": { "from_item": "reason" } },
|
|
109
|
+
"numeric_bounds": { "amount_cents": { "minimum": 1, "maximum": 2500 } },
|
|
110
|
+
"approval": { "mode": "human", "required_role": "billing_reviewer" },
|
|
111
|
+
"writeback": { "mode": "direct_sql" }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|