@synapsor/runner 1.1.1 → 1.4.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 +123 -1
- package/README.md +52 -31
- package/SECURITY.md +11 -0
- package/THREAT_MODEL.md +7 -4
- package/dist/cli.d.ts +5 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +8103 -2601
- package/docs/README.md +23 -3
- package/docs/benchmarks/bounded-set-local.md +27 -0
- package/docs/bounded-set-writeback.md +298 -0
- package/docs/capability-authoring.md +26 -8
- package/docs/conformance.md +12 -0
- package/docs/current-scope.md +12 -4
- package/docs/doctor.md +21 -7
- package/docs/dsl-reference.md +91 -5
- package/docs/getting-started-own-database.md +26 -3
- package/docs/guarded-crud-writeback.md +218 -0
- package/docs/limitations.md +30 -9
- package/docs/oss-vs-cloud.md +1 -1
- package/docs/production.md +52 -20
- package/docs/release-notes.md +105 -2
- package/docs/release-policy.md +1 -1
- package/docs/result-envelope-v2.md +20 -6
- package/docs/result-envelope-v3.md +43 -0
- package/docs/result-envelope-v4.md +47 -0
- package/docs/reversible-change-sets.md +151 -0
- package/docs/rfcs/004-guarded-crud-receipt-authority.md +165 -0
- package/docs/rfcs/005-bounded-set-writeback.md +164 -0
- package/docs/rfcs/006-reviewed-reversible-change-sets.md +152 -0
- package/docs/runner-config-reference.md +83 -9
- package/docs/running-a-runner-fleet.md +2 -1
- package/docs/security-boundary.md +36 -9
- package/docs/why-synapsor-vs-app-guardrails.md +169 -0
- package/docs/writeback-executors.md +12 -11
- package/examples/runner-fleet/seed/mysql.sql +47 -0
- package/examples/runner-fleet/seed/postgres.sql +48 -0
- package/examples/support-plan-credit/README.md +31 -0
- package/examples/support-plan-credit/contract.synapsor.sql +26 -0
- package/examples/support-plan-credit/expected-output/tools-preview.txt +1 -0
- package/examples/support-plan-credit/seed/001_seed.sql +14 -1
- package/examples/support-plan-credit/synapsor.contract.json +101 -1
- package/examples/support-plan-credit/synapsor.runner.json +7 -1
- package/fixtures/protocol/MANIFEST.json +131 -1
- package/fixtures/protocol/change-set.bounded-update.v3.json +57 -0
- package/fixtures/protocol/change-set.delete.v2.json +31 -0
- package/fixtures/protocol/change-set.insert.v2.json +36 -0
- package/fixtures/protocol/change-set.update.v2.json +32 -0
- package/fixtures/protocol/compensation-change-set.update.v1.json +40 -0
- package/fixtures/protocol/execution-receipt.bounded-update-applied.v3.json +39 -0
- package/fixtures/protocol/execution-receipt.compensation-update-applied.v4.json +37 -0
- package/fixtures/protocol/execution-receipt.delete-applied.v2.json +25 -0
- package/fixtures/protocol/execution-receipt.insert-applied.v2.json +24 -0
- package/fixtures/protocol/execution-receipt.reconciliation-required.v2.json +25 -0
- package/fixtures/protocol/execution-receipt.update-applied.v2.json +25 -0
- package/fixtures/protocol/writeback-job.bounded-update.v3.json +43 -0
- package/fixtures/protocol/writeback-job.compensation-update.v4.json +34 -0
- package/fixtures/protocol/writeback-job.delete.v2.json +22 -0
- package/fixtures/protocol/writeback-job.insert.v2.json +28 -0
- package/fixtures/protocol/writeback-job.update.v2.json +24 -0
- package/package.json +2 -1
- package/schemas/change-set.v2.schema.json +245 -0
- package/schemas/change-set.v3.schema.json +112 -0
- package/schemas/compensation-change-set.v1.schema.json +32 -0
- package/schemas/execution-receipt.v2.schema.json +106 -0
- package/schemas/execution-receipt.v3.schema.json +40 -0
- package/schemas/execution-receipt.v4.schema.json +22 -0
- package/schemas/inverse-descriptor.v1.schema.json +46 -0
- package/schemas/synapsor.runner.schema.json +132 -2
- package/schemas/writeback-job.v2.schema.json +238 -0
- package/schemas/writeback-job.v3.schema.json +53 -0
- package/schemas/writeback-job.v4.schema.json +17 -0
package/docs/README.md
CHANGED
|
@@ -24,6 +24,10 @@ no-database demo, wire your database, then read deeper concepts.
|
|
|
24
24
|
## 02 Why Raw SQL Is Dangerous
|
|
25
25
|
|
|
26
26
|
- [Security Boundary](security-boundary.md): what the model can and cannot see.
|
|
27
|
+
- [Why Synapsor Over Prompt And Application
|
|
28
|
+
Guardrails](why-synapsor-vs-app-guardrails.md): where SQL authority lives,
|
|
29
|
+
what a hand-built semantic tool already gets right, and when the shared
|
|
30
|
+
contract, approval, receipt, and replay layer is worth adopting.
|
|
27
31
|
- [MCP Audit](mcp-audit.md): static review for risky database MCP tools such as
|
|
28
32
|
`execute_sql`, broad query tools, model-controlled tenant filters, or
|
|
29
33
|
model-facing approval/commit tools.
|
|
@@ -45,6 +49,14 @@ no-database demo, wire your database, then read deeper concepts.
|
|
|
45
49
|
links to the canonical own-database guide.
|
|
46
50
|
- [Doctor](doctor.md): redacted setup checks, handler probes, direct SQL
|
|
47
51
|
writeback probes, and receipt-table guidance.
|
|
52
|
+
- [Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md): native
|
|
53
|
+
INSERT/UPDATE/DELETE, receipt modes, crash semantics, privileges, and
|
|
54
|
+
reconciliation.
|
|
55
|
+
- [Bounded Set Writeback](bounded-set-writeback.md): fixed-predicate set
|
|
56
|
+
UPDATE/DELETE, exact-review batch INSERT, mandatory caps, atomicity, and
|
|
57
|
+
exact receipts.
|
|
58
|
+
- [Reviewed Reversible Change Sets](reversible-change-sets.md): opt-in bounded
|
|
59
|
+
inverse capture and the separate operator proposal/approval/apply flow.
|
|
48
60
|
|
|
49
61
|
## 05 Generate Capabilities
|
|
50
62
|
|
|
@@ -89,6 +101,11 @@ no-database demo, wire your database, then read deeper concepts.
|
|
|
89
101
|
|
|
90
102
|
- [Result Envelope v2](result-envelope-v2.md): stable
|
|
91
103
|
`ok`/`summary`/`data`/`proposal`/`error` MCP tool results.
|
|
104
|
+
- [Result Envelope v3](result-envelope-v3.md): frozen-set jobs and receipts
|
|
105
|
+
with every bounded member identity and safe digest.
|
|
106
|
+
- [Compensation Protocol v4](result-envelope-v4.md): reviewed inverse
|
|
107
|
+
descriptors, compensation proposals/jobs/receipts, lineage, and
|
|
108
|
+
reconciliation semantics.
|
|
92
109
|
- [Store Lifecycle](store-lifecycle.md): active-store leases, prune safety,
|
|
93
110
|
deleted-store behavior, and concurrent server guardrails.
|
|
94
111
|
- `synapsor-runner activity search`, `evidence`, `query-audit`, `receipts`,
|
|
@@ -130,7 +147,10 @@ no-database demo, wire your database, then read deeper concepts.
|
|
|
130
147
|
- RFC source context:
|
|
131
148
|
[001 result envelope](rfcs/001-result-envelope-v2.md),
|
|
132
149
|
[002 handler helper](rfcs/002-app-owned-handler-helper.md),
|
|
133
|
-
[003 integrator teardown](rfcs/003-integrator-feedback-teardown.md)
|
|
150
|
+
[003 integrator teardown](rfcs/003-integrator-feedback-teardown.md),
|
|
151
|
+
[004 guarded CRUD and receipt authority](rfcs/004-guarded-crud-receipt-authority.md),
|
|
152
|
+
[005 bounded set writeback](rfcs/005-bounded-set-writeback.md), and
|
|
153
|
+
[006 reviewed reversible change sets](rfcs/006-reviewed-reversible-change-sets.md).
|
|
134
154
|
|
|
135
155
|
The public docs intentionally stay task-first. Historical implementation
|
|
136
156
|
reports, release checklists, and internal planning notes are not part of the
|
|
@@ -144,8 +164,8 @@ getting-started path.
|
|
|
144
164
|
database.
|
|
145
165
|
- Writeback: execution of an approved proposal outside the model-facing MCP
|
|
146
166
|
surface.
|
|
147
|
-
- Executor: Runner's guarded one-row
|
|
148
|
-
approved business transactions.
|
|
167
|
+
- Executor: Runner's guarded one-row/bounded-set database adapter or an
|
|
168
|
+
app-owned handler for richer approved business transactions.
|
|
149
169
|
|
|
150
170
|
## Repository Map
|
|
151
171
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Bounded Set Local Measurements
|
|
2
|
+
|
|
3
|
+
These measurements are test evidence, not throughput claims or capacity
|
|
4
|
+
guidance. They record one run of `corepack pnpm test:bounded-set` on 2026-07-13
|
|
5
|
+
using synthetic rows and disposable local Docker databases.
|
|
6
|
+
|
|
7
|
+
Environment:
|
|
8
|
+
|
|
9
|
+
- Linux laptop, Intel Core i7-13800H, 20 logical CPUs, 30 GiB RAM;
|
|
10
|
+
- Node.js 22.22.2 and pnpm 10.14.0;
|
|
11
|
+
- Docker 29.5.2;
|
|
12
|
+
- PostgreSQL 16 and MySQL 8 containers;
|
|
13
|
+
- source-database receipt authority with an administrator-precreated receipt
|
|
14
|
+
table;
|
|
15
|
+
- one sequential set UPDATE per measurement, including connection setup,
|
|
16
|
+
source receipt, lock/preflight, transaction, and exact receipt generation.
|
|
17
|
+
|
|
18
|
+
| Engine | 1 row | 10 rows | 100 rows |
|
|
19
|
+
| --- | ---: | ---: | ---: |
|
|
20
|
+
| PostgreSQL | 30.42 ms | 53.88 ms | 154.90 ms |
|
|
21
|
+
| MySQL | 25.30 ms | 53.91 ms | 163.20 ms |
|
|
22
|
+
|
|
23
|
+
These figures are not portable across hardware, network topology, source
|
|
24
|
+
indexes, lock contention, triggers, database configuration, or receipt mode.
|
|
25
|
+
The claim supported by this gate is only that execution stays bounded and the
|
|
26
|
+
hard 100-row ceiling is exercised on both adapters. Operators must benchmark
|
|
27
|
+
their own reviewed contracts and database topology.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Bounded Set Writeback
|
|
2
|
+
|
|
3
|
+
Synapsor Runner can apply a deliberately narrow class of reviewed
|
|
4
|
+
multi-row database changes to PostgreSQL and MySQL:
|
|
5
|
+
|
|
6
|
+
- fixed-predicate set `UPDATE`;
|
|
7
|
+
- fixed-predicate set `DELETE`;
|
|
8
|
+
- exact-review batch `INSERT`.
|
|
9
|
+
|
|
10
|
+
This is not model-generated SQL and it is not a generic batch API. The model
|
|
11
|
+
can ask to run a reviewed business action, but it cannot choose a table,
|
|
12
|
+
column, operator, ordering, predicate, tenant, or unbounded set.
|
|
13
|
+
|
|
14
|
+
## Safety invariant
|
|
15
|
+
|
|
16
|
+
The worst action available to a prompt-injected model is to request one
|
|
17
|
+
contract-authored rule, against the trusted tenant, up to the reviewer-authored
|
|
18
|
+
row and value caps. Before approval, Runner freezes the exact ordered members.
|
|
19
|
+
Apply later touches only those members in one transaction and records every
|
|
20
|
+
identity and bounded digest.
|
|
21
|
+
|
|
22
|
+
Every bounded set requires:
|
|
23
|
+
|
|
24
|
+
1. a fixed typed selection for existing-row UPDATE/DELETE, or the complete
|
|
25
|
+
reviewed item array for batch INSERT;
|
|
26
|
+
2. `MAX ROWS n`, where `1 <= n <= 100`;
|
|
27
|
+
3. at least one aggregate `MAX TOTAL` bound;
|
|
28
|
+
4. trusted tenant binding;
|
|
29
|
+
5. exact version guards and integer advancement for set UPDATE;
|
|
30
|
+
6. source-unique per-item identities for batch INSERT;
|
|
31
|
+
7. human/operator approval outside MCP;
|
|
32
|
+
8. one atomic source transaction and an exact affected-row count;
|
|
33
|
+
9. source or Runner-ledger receipts with the documented crash semantics.
|
|
34
|
+
|
|
35
|
+
A row cap is a rejection threshold, never `LIMIT n` truncation. Proposal reads
|
|
36
|
+
fetch at most `n + 1`; finding the extra row rejects before proposal
|
|
37
|
+
persistence. Aggregate overflow also rejects before persistence.
|
|
38
|
+
|
|
39
|
+
## DSL examples
|
|
40
|
+
|
|
41
|
+
Fixed set UPDATE:
|
|
42
|
+
|
|
43
|
+
```sql
|
|
44
|
+
PROPOSE ACTION close_overdue UPDATE SET
|
|
45
|
+
SELECT WHERE status = 'overdue'
|
|
46
|
+
MAX ROWS 10
|
|
47
|
+
MAX TOTAL balance_cents BEFORE 50000
|
|
48
|
+
ALLOW WRITE status
|
|
49
|
+
PATCH status = 'closed'
|
|
50
|
+
ADVANCE VERSION version USING INTEGER INCREMENT
|
|
51
|
+
APPROVAL ROLE billing_reviewer
|
|
52
|
+
WRITEBACK DIRECT SQL
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The selection is a contract literal. It is not an argument and is never taken
|
|
56
|
+
from the model. The first release supports equality terms joined by `AND`.
|
|
57
|
+
|
|
58
|
+
Exact-review batch INSERT:
|
|
59
|
+
|
|
60
|
+
```sql
|
|
61
|
+
ARG items ROWS MAX 10 REQUIRED
|
|
62
|
+
ITEM FIELD items.id STRING REQUIRED MAX LENGTH 128
|
|
63
|
+
ITEM FIELD items.external_id STRING REQUIRED MAX LENGTH 128
|
|
64
|
+
ITEM FIELD items.amount_cents NUMBER REQUIRED MIN 1 MAX 2500
|
|
65
|
+
ITEM FIELD items.reason STRING REQUIRED MAX LENGTH 500
|
|
66
|
+
|
|
67
|
+
PROPOSE ACTION create_credits INSERT SET
|
|
68
|
+
BATCH ITEMS FROM ARG items
|
|
69
|
+
MAX ROWS 10
|
|
70
|
+
MAX TOTAL amount_cents AFTER 25000
|
|
71
|
+
DEDUP KEY tenant_id = TRUSTED TENANT, id = ITEM id, external_id = ITEM external_id
|
|
72
|
+
ALLOW WRITE amount_cents, reason
|
|
73
|
+
PATCH amount_cents = ITEM amount_cents
|
|
74
|
+
PATCH reason = ITEM reason
|
|
75
|
+
APPROVAL ROLE billing_reviewer
|
|
76
|
+
WRITEBACK DIRECT SQL
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The reviewer sees every allowlisted candidate item before approval. The source
|
|
80
|
+
must enforce the declared identity with a primary or unique constraint.
|
|
81
|
+
|
|
82
|
+
Set DELETE uses `DELETE SET`, a fixed selection, `MAX ROWS`, `MAX TOTAL`, and
|
|
83
|
+
an exact conflict guard. It has no patch. Runner rejects hard DELETE if it
|
|
84
|
+
cannot prove trigger/FK visibility or detects write triggers or widening
|
|
85
|
+
cascades. Prefer a set UPDATE of `deleted_at` or status when possible.
|
|
86
|
+
|
|
87
|
+
## Worked contract-to-apply example
|
|
88
|
+
|
|
89
|
+
This PostgreSQL example closes two overdue tickets. MySQL is supported with
|
|
90
|
+
the same contract semantics; change the source engine and schema/database name
|
|
91
|
+
to match the inspected MySQL object.
|
|
92
|
+
|
|
93
|
+
Create the fixture with an administrator account, then give the Runner reader
|
|
94
|
+
`SELECT` and its separate writer only `SELECT, UPDATE` on this table:
|
|
95
|
+
|
|
96
|
+
```sql
|
|
97
|
+
CREATE TABLE public.service_tickets (
|
|
98
|
+
id bigint PRIMARY KEY,
|
|
99
|
+
tenant_id text NOT NULL,
|
|
100
|
+
status text NOT NULL,
|
|
101
|
+
cost_cents integer NOT NULL,
|
|
102
|
+
version integer NOT NULL
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
INSERT INTO public.service_tickets
|
|
106
|
+
(id, tenant_id, status, cost_cents, version)
|
|
107
|
+
VALUES
|
|
108
|
+
(3, 'acme', 'overdue', 8000, 1),
|
|
109
|
+
(4, 'acme', 'overdue', 15000, 1),
|
|
110
|
+
(99, 'globex', 'overdue', 49000, 1);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Save this as `tickets.synapsor.sql`:
|
|
114
|
+
|
|
115
|
+
```sql
|
|
116
|
+
CREATE AGENT CONTEXT local_operator
|
|
117
|
+
BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
|
|
118
|
+
BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
|
|
119
|
+
TENANT BINDING tenant_id
|
|
120
|
+
PRINCIPAL BINDING principal
|
|
121
|
+
END
|
|
122
|
+
|
|
123
|
+
CREATE CAPABILITY tickets.close_overdue
|
|
124
|
+
USING CONTEXT local_operator
|
|
125
|
+
SOURCE local_db
|
|
126
|
+
ON public.service_tickets
|
|
127
|
+
PRIMARY KEY id
|
|
128
|
+
TENANT KEY tenant_id
|
|
129
|
+
CONFLICT GUARD version
|
|
130
|
+
LOOKUP reason BY id
|
|
131
|
+
ARG reason STRING REQUIRED MAX LENGTH 100
|
|
132
|
+
ALLOW READ id, tenant_id, status, cost_cents, version
|
|
133
|
+
REQUIRE EVIDENCE
|
|
134
|
+
PROPOSE ACTION close_overdue UPDATE SET
|
|
135
|
+
SELECT WHERE status = 'overdue'
|
|
136
|
+
MAX ROWS 10
|
|
137
|
+
MAX TOTAL cost_cents BEFORE 50000
|
|
138
|
+
ALLOW WRITE status
|
|
139
|
+
PATCH status = 'closed'
|
|
140
|
+
ADVANCE VERSION version USING INTEGER INCREMENT
|
|
141
|
+
APPROVAL ROLE ops_manager
|
|
142
|
+
WRITEBACK DIRECT SQL
|
|
143
|
+
END
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Compile the contract and create `synapsor.runner.json`:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
synapsor-runner dsl compile ./tickets.synapsor.sql \
|
|
150
|
+
--out ./synapsor.contract.json --strict
|
|
151
|
+
synapsor-runner contract validate ./synapsor.contract.json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"version": 1,
|
|
157
|
+
"mode": "review",
|
|
158
|
+
"storage": { "sqlite_path": "./.synapsor/local.db" },
|
|
159
|
+
"sources": {
|
|
160
|
+
"local_db": {
|
|
161
|
+
"engine": "postgres",
|
|
162
|
+
"read_url_env": "SYNAPSOR_DATABASE_READ_URL",
|
|
163
|
+
"write_url_env": "SYNAPSOR_DATABASE_WRITE_URL",
|
|
164
|
+
"statement_timeout_ms": 3000,
|
|
165
|
+
"receipts": { "authority": "runner_ledger" }
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"contracts": ["./synapsor.contract.json"]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Load database URLs from your shell or secret manager. The config stores only
|
|
173
|
+
environment-variable names. Trusted tenant/principal values are process-owned,
|
|
174
|
+
not tool arguments:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
export SYNAPSOR_TENANT_ID=acme
|
|
178
|
+
export SYNAPSOR_PRINCIPAL=local_operator
|
|
179
|
+
|
|
180
|
+
synapsor-runner config validate --config ./synapsor.runner.json
|
|
181
|
+
synapsor-runner doctor --config ./synapsor.runner.json --check-writeback
|
|
182
|
+
synapsor-runner propose tickets.close_overdue \
|
|
183
|
+
--json '{"reason":"reviewed overdue-ticket close"}' \
|
|
184
|
+
--config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
185
|
+
synapsor-runner proposals show latest --store ./.synapsor/local.db --details
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
At this point IDs `3` and `4` are frozen in the proposal, but both source rows
|
|
189
|
+
are still `overdue` at version `1`; the `globex` row is outside trusted tenant
|
|
190
|
+
scope. Approval and apply remain operator-side commands and are not MCP tools:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
synapsor-runner proposals approve latest --actor ops_manager --yes \
|
|
194
|
+
--store ./.synapsor/local.db
|
|
195
|
+
synapsor-runner apply latest --config ./synapsor.runner.json \
|
|
196
|
+
--store ./.synapsor/local.db
|
|
197
|
+
synapsor-runner receipts list --proposal <proposal_id> \
|
|
198
|
+
--store ./.synapsor/local.db
|
|
199
|
+
synapsor-runner replay show --proposal <proposal_id> --details \
|
|
200
|
+
--store ./.synapsor/local.db
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Exactly IDs `3` and `4` become `closed` at version `2` in one transaction.
|
|
204
|
+
The receipt/replay list both safe primary-key identities and their bounded
|
|
205
|
+
digests. ID `99` is unchanged.
|
|
206
|
+
|
|
207
|
+
To test drift on a freshly seeded copy, create the proposal, then use a
|
|
208
|
+
database-operator session to increment one frozen row's version before
|
|
209
|
+
approval. `apply` returns `SET_DRIFT_CONFLICT`; the other frozen row remains
|
|
210
|
+
unchanged because no partial set mutation is committed:
|
|
211
|
+
|
|
212
|
+
```sql
|
|
213
|
+
UPDATE public.service_tickets SET version = version + 1 WHERE id = 4;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The example uses `runner_ledger`, which creates no receipt table in the source
|
|
217
|
+
database. For one local process, the local store is the authority; a fleet must
|
|
218
|
+
use authoritative shared-Postgres `runtime_store`. `source_db` authority
|
|
219
|
+
instead writes the mutation and receipt atomically in one source transaction
|
|
220
|
+
and requires its fixed precreated or auto-migrated receipt table. See
|
|
221
|
+
[Guarded CRUD receipt authority](guarded-crud-writeback.md).
|
|
222
|
+
|
|
223
|
+
## Proposal and apply behavior
|
|
224
|
+
|
|
225
|
+
Proposal creation stores:
|
|
226
|
+
|
|
227
|
+
- the exact ordered primary keys and trusted tenant;
|
|
228
|
+
- every exact expected version;
|
|
229
|
+
- allowlisted before/after values or bounded digests;
|
|
230
|
+
- reviewed row count and aggregate values;
|
|
231
|
+
- a digest over the complete frozen set;
|
|
232
|
+
- pending human/operator approval.
|
|
233
|
+
|
|
234
|
+
Member and set digests use SHA-256 over JSON whose object keys are sorted
|
|
235
|
+
recursively. Array order remains significant because it is the reviewed,
|
|
236
|
+
deterministic primary-key order. JSON strings, finite numbers, booleans, and
|
|
237
|
+
null retain their protocol representation; unsupported runtime objects and
|
|
238
|
+
non-finite values are rejected rather than stringified implicitly. Runner
|
|
239
|
+
1.4.1 also verifies the narrowly known deterministic raw-object order emitted
|
|
240
|
+
by 1.4.0, reconstructed from the complete stored reviewed data, so unchanged
|
|
241
|
+
1.4.0 proposals remain applyable without weakening the drift checks.
|
|
242
|
+
|
|
243
|
+
Apply locks the frozen rows in deterministic primary-key order, rechecks every
|
|
244
|
+
reviewed value/version, performs every member mutation in one transaction, and
|
|
245
|
+
requires the affected count to equal the frozen count. One missing/stale row or
|
|
246
|
+
one database error rolls back the whole set.
|
|
247
|
+
|
|
248
|
+
Set `sources.<name>.statement_timeout_ms` to bound source waits. PostgreSQL
|
|
249
|
+
uses transaction-local statement and lock timeouts. MySQL applies the value to
|
|
250
|
+
read/preflight execution and rounds it up to whole seconds for InnoDB lock
|
|
251
|
+
waits; MySQL does not offer the same general DML statement timeout as
|
|
252
|
+
PostgreSQL.
|
|
253
|
+
|
|
254
|
+
The protocol-v3 receipt and replay include every primary key plus the bounded
|
|
255
|
+
before/after or tombstone digests. Kept-out fields are never added merely to
|
|
256
|
+
support a set operation.
|
|
257
|
+
|
|
258
|
+
## Receipt authority and ambiguity
|
|
259
|
+
|
|
260
|
+
`source_db` authority commits the mutation and receipt in the same source
|
|
261
|
+
transaction. It gives the strongest retry classification.
|
|
262
|
+
|
|
263
|
+
`runner_ledger` authority creates no source receipt table, but no atomic
|
|
264
|
+
transaction spans the source and Runner ledger. A process loss after source
|
|
265
|
+
commit can therefore produce `reconciliation_required`. Runner does not retry
|
|
266
|
+
or guess. The operator reconciliation path re-inspects only the frozen,
|
|
267
|
+
allowlisted identities and records an immutable decision.
|
|
268
|
+
|
|
269
|
+
## Explicit boundary
|
|
270
|
+
|
|
271
|
+
Use an [app-owned executor](writeback-executors.md) for:
|
|
272
|
+
|
|
273
|
+
- model-supplied or free-form predicates;
|
|
274
|
+
- ranges, wildcards, ordering, subqueries, or dynamic identifiers;
|
|
275
|
+
- more than 100 rows or any unbounded batch;
|
|
276
|
+
- UPSERT/MERGE, DDL, stored procedures, or cross-table/database transactions;
|
|
277
|
+
- external API calls, events, files, emails, payments, or other side effects;
|
|
278
|
+
- a hard DELETE whose trigger/cascade effects cannot be proven bounded.
|
|
279
|
+
|
|
280
|
+
Policy auto-approval is not supported for bounded sets. Every set proposal
|
|
281
|
+
requires a verified human/operator decision.
|
|
282
|
+
|
|
283
|
+
## Verification
|
|
284
|
+
|
|
285
|
+
Run the disposable-engine gate:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
corepack pnpm test:bounded-set
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
It verifies both PostgreSQL and MySQL: the exact DSL/contract path under both
|
|
292
|
+
receipt authorities; cap+1 and aggregate rejection before persistence; exact
|
|
293
|
+
UPDATE/DELETE; batch INSERT; idempotent retry; independent version, predicate,
|
|
294
|
+
aggregate, writable-value, missing-member, and tenant drift; injected mid-set
|
|
295
|
+
rollback; insert dedup/atomicity; delete trigger/cascade refusal; exact receipt
|
|
296
|
+
members; Runner-ledger reconciliation; and 1/10/100-row bounds. See the
|
|
297
|
+
[local benchmark note](benchmarks/bounded-set-local.md) and the normative
|
|
298
|
+
[safety RFC](rfcs/005-bounded-set-writeback.md).
|
|
@@ -138,6 +138,7 @@ reviewed runner JSON capabilities. Current parity:
|
|
|
138
138
|
| proposal `approval` | `APPROVAL ROLE billing_lead` | 0.1 | Local mode records the required role; enforcement is still outside the model-facing MCP tool. |
|
|
139
139
|
| proposal `approval.required_approvals` | `REQUIRE 2 APPROVALS` | 1.1 | Optional 1..10 distinct-reviewer quorum; defaults to 1. |
|
|
140
140
|
| proposal `writeback` | `WRITEBACK DIRECT SQL`, `WRITEBACK APP HANDLER EXECUTOR name`, `WRITEBACK CLOUD WORKER`, `WRITEBACK NONE` | 0.1.7 | Handler URLs/tokens stay in `synapsor.runner.json`; contracts carry only the handler name. |
|
|
141
|
+
| proposal `reversibility` | `REVERSIBLE` | 1.4 | Direct SQL only. Captures a bounded inverse after unambiguous apply; operator `revert` creates a new independently approved proposal. |
|
|
141
142
|
| evidence options | `REQUIRE EVIDENCE` | 0.1 | Detailed evidence sources/handle prefixes are not expressible in DSL yet; use embedded JSON or generated contract JSON for those. |
|
|
142
143
|
|
|
143
144
|
## Direct Runner Config Path
|
|
@@ -319,7 +320,11 @@ Runner rejects model-facing trust-scope arguments.
|
|
|
319
320
|
|
|
320
321
|
## Direct SQL Writeback
|
|
321
322
|
|
|
322
|
-
Use direct SQL writeback
|
|
323
|
+
Use direct SQL writeback for reviewed guarded single-row INSERT, UPDATE, or
|
|
324
|
+
DELETE proposals. Version 1.3 also supports the narrower [bounded set
|
|
325
|
+
form](bounded-set-writeback.md): fixed-predicate UPDATE/DELETE or complete-item
|
|
326
|
+
batch INSERT with mandatory row/value caps, a frozen exact set, human approval,
|
|
327
|
+
atomic apply, and exact receipts.
|
|
323
328
|
Runner validates:
|
|
324
329
|
|
|
325
330
|
- fixed table and column names;
|
|
@@ -331,19 +336,26 @@ Runner validates:
|
|
|
331
336
|
- one affected row;
|
|
332
337
|
- idempotency receipt.
|
|
333
338
|
|
|
334
|
-
|
|
335
|
-
|
|
339
|
+
INSERT additionally requires a source-unique dedup key. DELETE requires an exact
|
|
340
|
+
version guard and fails closed on widening cascades or write triggers.
|
|
341
|
+
|
|
342
|
+
Runner does not expose generic/model-generated SQL, DDL, UPSERT, a model-chosen
|
|
343
|
+
predicate, unbounded writes, or cross-table transactions. Set writes that
|
|
344
|
+
cannot meet every bounded-set invariant stay on the app-owned executor path.
|
|
336
345
|
|
|
337
346
|
Direct SQL writeback uses the source `write_url_env`, such as
|
|
338
|
-
`SYNAPSOR_DATABASE_WRITE_URL`.
|
|
339
|
-
|
|
340
|
-
|
|
347
|
+
`SYNAPSOR_DATABASE_WRITE_URL`. Select atomic `source_db` receipts (precreated or
|
|
348
|
+
auto-migrated) or zero-source-schema `runner_ledger` receipts. Ledger authority
|
|
349
|
+
has an explicit post-source-commit crash window and reconciliation workflow; it
|
|
350
|
+
is not distributed exactly-once. See
|
|
351
|
+
[Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md).
|
|
341
352
|
|
|
342
353
|
## App-Owned Executors
|
|
343
354
|
|
|
344
355
|
Use an app-owned executor when an approved proposal needs richer business work:
|
|
345
|
-
|
|
346
|
-
or
|
|
356
|
+
inserting an outbox event, updating multiple app tables, calling your own
|
|
357
|
+
service, or creating a row whose source constraints cannot satisfy native
|
|
358
|
+
single-row INSERT guards.
|
|
347
359
|
|
|
348
360
|
In DSL, keep the reviewed business contract portable and name the executor:
|
|
349
361
|
|
|
@@ -435,3 +447,9 @@ Commit authority stays outside the model:
|
|
|
435
447
|
```text
|
|
436
448
|
human/operator approval -> guarded writeback or app-owned handler -> receipt/replay
|
|
437
449
|
```
|
|
450
|
+
|
|
451
|
+
If your application already exposes fixed parameterized functions, that is a
|
|
452
|
+
good foundation rather than an anti-pattern. Read [Why Synapsor Over Prompt And
|
|
453
|
+
Application Guardrails](why-synapsor-vs-app-guardrails.md) to decide whether
|
|
454
|
+
you also need Runner's shared contract, trusted context, evidence, approval,
|
|
455
|
+
receipt, replay, and compensation lifecycle.
|
package/docs/conformance.md
CHANGED
|
@@ -29,12 +29,24 @@ Current fixture groups:
|
|
|
29
29
|
- `auto-approval`
|
|
30
30
|
- `aggregate-policy-limits`
|
|
31
31
|
- `numeric-bounds`
|
|
32
|
+
- `bounded-set-threats`
|
|
33
|
+
- `reversible-change-sets`
|
|
32
34
|
|
|
33
35
|
The fixture set is intentionally small in 0.1. It covers the runner-supported
|
|
34
36
|
semantic surface first: trusted context, scoped reads, evidence handles,
|
|
35
37
|
proposal boundaries, kept-out fields, manual approval, and replay envelopes.
|
|
36
38
|
The aggregate-policy fixture additionally proves that reviewed daily ceilings
|
|
37
39
|
fall back to human review atomically and record the limit that tripped.
|
|
40
|
+
The bounded-set fixture maps threats R1-R7 to executable expectations: fixed
|
|
41
|
+
selection, count/value caps, frozen-version drift checks, atomic rollback,
|
|
42
|
+
exact receipts, hard-delete side-effect refusal, and human approval. Adapter
|
|
43
|
+
tests and `corepack pnpm test:bounded-set` complete the live PostgreSQL/MySQL
|
|
44
|
+
matrix.
|
|
45
|
+
The reversible-change-set fixture proves that undo is a new reviewed
|
|
46
|
+
compensation proposal, not rollback: apply-time receipts capture only
|
|
47
|
+
allowlisted inverse data, compensation uses fresh guards and exact members,
|
|
48
|
+
ambiguous outcomes fail closed pending reconciliation, and hard delete reports
|
|
49
|
+
a specific best-effort-unavailable reason.
|
|
38
50
|
|
|
39
51
|
Additional 0.1 parity coverage currently lives in tests and verification
|
|
40
52
|
scripts rather than separate `cloud-push/` or `dsl-json-parity/` conformance
|
package/docs/current-scope.md
CHANGED
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
The canonical scope page is [Current Limitations](limitations.md).
|
|
4
4
|
|
|
5
|
-
Current `1.
|
|
5
|
+
Current `1.4` scope:
|
|
6
6
|
|
|
7
7
|
- local semantic MCP tools for Postgres/MySQL-backed business actions;
|
|
8
8
|
- schema inspection and guided config generation;
|
|
9
9
|
- trusted context from environment/session values;
|
|
10
10
|
- evidence handles, query audit, proposals, receipts, and local replay;
|
|
11
|
-
- guarded single-row `UPDATE` writeback
|
|
11
|
+
- guarded single-row `INSERT`, `UPDATE`, and `DELETE` writeback with explicit
|
|
12
|
+
receipt authority;
|
|
13
|
+
- fixed-predicate set `UPDATE`/`DELETE` and exact-review batch `INSERT`, with
|
|
14
|
+
mandatory row/value caps, frozen members, human approval, atomic execution,
|
|
15
|
+
and protocol-v3 exact receipts;
|
|
16
|
+
- opt-in reviewed compensation for direct SQL UPDATE, INSERT, soft-delete, and
|
|
17
|
+
exact frozen sets, using a separate operator proposal and protocol-v4 receipt;
|
|
12
18
|
- app-owned `http_handler` and `command_handler` executors for richer approved
|
|
13
19
|
business transactions;
|
|
14
20
|
- stdio MCP, Streamable HTTP MCP, and a small JSON-RPC bridge.
|
|
@@ -25,9 +31,11 @@ Out of scope:
|
|
|
25
31
|
|
|
26
32
|
- raw `execute_sql`;
|
|
27
33
|
- model-generated SQL;
|
|
28
|
-
-
|
|
29
|
-
-
|
|
34
|
+
- UPSERT, DDL, model-generated predicates, or unguarded INSERT/DELETE;
|
|
35
|
+
- model-generated, unbounded, or cross-table set writeback;
|
|
30
36
|
- physical branching of external Postgres/MySQL;
|
|
37
|
+
- automatic rollback/time travel and inferred compensation for app-owned or
|
|
38
|
+
external effects;
|
|
31
39
|
- self-hosted Synapsor Cloud;
|
|
32
40
|
- unbounded or multi-region shared-ledger scale and a managed Runner fleet;
|
|
33
41
|
- production SLA or compliance certification.
|
package/docs/doctor.md
CHANGED
|
@@ -44,8 +44,9 @@ Idempotency-Key
|
|
|
44
44
|
|
|
45
45
|
## Direct SQL Writeback Checks
|
|
46
46
|
|
|
47
|
-
For direct
|
|
48
|
-
the receipt
|
|
47
|
+
For direct guarded single-row CRUD or bounded-set writeback, add
|
|
48
|
+
`--check-writeback` after reviewing the selected receipt mode and
|
|
49
|
+
operation-specific grants:
|
|
49
50
|
|
|
50
51
|
```bash
|
|
51
52
|
synapsor-runner doctor --config synapsor.runner.json --check-writeback
|
|
@@ -55,17 +56,23 @@ This connects with the trusted writer env var named by `write_url_env` and
|
|
|
55
56
|
checks:
|
|
56
57
|
|
|
57
58
|
- writer database connectivity;
|
|
58
|
-
-
|
|
59
|
+
- source receipt migration/permissions when authority is `source_db`;
|
|
60
|
+
- no source receipt DDL/DML when authority is `runner_ledger`;
|
|
59
61
|
- rollback-only access to each configured proposal target table;
|
|
60
|
-
-
|
|
62
|
+
- operation-specific version, unique/dedup, generated-column, trigger,
|
|
63
|
+
cascade, RLS, and DML prerequisites.
|
|
64
|
+
|
|
65
|
+
For bounded sets, the normal doctor report also identifies operation kind,
|
|
66
|
+
fixed selection or exact batch source, row cap, aggregate bounds, and the
|
|
67
|
+
mandatory human/operator approval boundary. It fails validation before any
|
|
68
|
+
proposal exists when those portable guards are incomplete.
|
|
61
69
|
|
|
62
70
|
The target-table probe uses fixed schema/table/column identifiers from the
|
|
63
71
|
reviewed config. It does not accept model SQL, user SQL, arbitrary table names,
|
|
64
72
|
or arbitrary column names. It runs inside a transaction and rolls back.
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
steady-state
|
|
68
|
-
schema `CREATE`:
|
|
74
|
+
For `source_db` + `precreated`, an administrator creates the receipt table and
|
|
75
|
+
grants steady-state access. Doctor never executes DDL in this mode:
|
|
69
76
|
|
|
70
77
|
```bash
|
|
71
78
|
synapsor-runner writeback migration --engine postgres --schema synapsor
|
|
@@ -79,6 +86,13 @@ synapsor-runner writeback migration --engine mysql --schema appdb
|
|
|
79
86
|
synapsor-runner writeback grants --engine mysql --schema appdb --writer-role "'app_writer'@'%'"
|
|
80
87
|
```
|
|
81
88
|
|
|
89
|
+
Use `source_db` + `auto_migrate` only when the writer may create the fixed
|
|
90
|
+
receipt table. Use `runner_ledger` for no source receipt table; doctor then
|
|
91
|
+
checks the local/small-fleet topology and crash-reconciliation prerequisites.
|
|
92
|
+
See [Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md).
|
|
93
|
+
For set-specific prerequisites, see [Bounded Set
|
|
94
|
+
Writeback](bounded-set-writeback.md).
|
|
95
|
+
|
|
82
96
|
Use an app-owned `http_handler` or `command_handler` executor when your
|
|
83
97
|
application should own richer business writes or receipt storage.
|
|
84
98
|
|