@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
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# RFC 005: Bounded Set Writeback
|
|
2
|
+
|
|
3
|
+
Status: implementation gate
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Runner 1.3 may execute a reviewed set write only when the set is fixed by the
|
|
8
|
+
contract, frozen before approval, bounded by both row count and business value,
|
|
9
|
+
and applied atomically. A row cap by itself is not a safety boundary.
|
|
10
|
+
|
|
11
|
+
This RFC authorizes three direct operations:
|
|
12
|
+
|
|
13
|
+
- fixed-predicate set UPDATE;
|
|
14
|
+
- fixed-predicate set DELETE;
|
|
15
|
+
- exact-review batch INSERT.
|
|
16
|
+
|
|
17
|
+
Free-form predicates, model-selected columns or operators, unbounded sets,
|
|
18
|
+
UPSERT, DDL, cross-table work, and external effects remain app-owned executor
|
|
19
|
+
work.
|
|
20
|
+
|
|
21
|
+
## Canonical Model
|
|
22
|
+
|
|
23
|
+
Set operations are explicit. They never reuse a single-row lookup by merely
|
|
24
|
+
raising `max_rows`.
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"operation": {
|
|
29
|
+
"kind": "update",
|
|
30
|
+
"cardinality": "set",
|
|
31
|
+
"selection": {
|
|
32
|
+
"all": [
|
|
33
|
+
{ "column": "status", "operator": "eq", "value": "overdue" }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"max_rows": 10,
|
|
37
|
+
"aggregate_bounds": [
|
|
38
|
+
{ "column": "balance_cents", "measure": "before", "maximum": 50000 }
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The first release accepts only contract literals in `selection`. The typed AST
|
|
45
|
+
reserves no raw SQL escape hatch. The model can trigger the reviewed capability
|
|
46
|
+
but cannot choose a predicate, column, operator, ordering, range, wildcard, or
|
|
47
|
+
set size.
|
|
48
|
+
|
|
49
|
+
Batch INSERT uses an explicitly typed bounded item-array argument. Every item
|
|
50
|
+
is fully materialized in the proposal, receives the trusted tenant, and has a
|
|
51
|
+
source-enforced unique dedup identity. A generic JSON blob is not accepted.
|
|
52
|
+
|
|
53
|
+
## Hard Limits
|
|
54
|
+
|
|
55
|
+
- `MAX ROWS` is mandatory and must be between 1 and 100.
|
|
56
|
+
- at least one aggregate value bound is mandatory;
|
|
57
|
+
- a proposal query fetches at most `MAX ROWS + 1` rows;
|
|
58
|
+
- at most 64 reviewed columns may be captured per row;
|
|
59
|
+
- before/after payloads and digests are bounded before persistence;
|
|
60
|
+
- overflow rejects the proposal; it is never truncated to the cap.
|
|
61
|
+
|
|
62
|
+
The implementation ceiling of 100 is a safety limit, not a throughput claim.
|
|
63
|
+
|
|
64
|
+
## Frozen Set
|
|
65
|
+
|
|
66
|
+
At proposal time Runner stores, in deterministic primary-key order:
|
|
67
|
+
|
|
68
|
+
- exact primary key;
|
|
69
|
+
- trusted tenant;
|
|
70
|
+
- expected version for UPDATE/DELETE;
|
|
71
|
+
- allowlisted before and after values;
|
|
72
|
+
- per-row before and after digests;
|
|
73
|
+
- count, aggregate measurements, and one set digest.
|
|
74
|
+
|
|
75
|
+
Apply never re-runs the broad selection predicate. It locks the frozen primary
|
|
76
|
+
keys in the same deterministic order, rechecks tenant and every expected
|
|
77
|
+
version, and mutates the complete set in one transaction. A missing or stale
|
|
78
|
+
member rolls back the whole transaction.
|
|
79
|
+
|
|
80
|
+
## Approval
|
|
81
|
+
|
|
82
|
+
All set operations require verified human/operator approval in 1.3. Policy
|
|
83
|
+
auto-approval is rejected rather than silently downgraded. Set hard DELETE and
|
|
84
|
+
batch INSERT are never auto-approved. This keeps row/value-aware policy design
|
|
85
|
+
out of the first release.
|
|
86
|
+
|
|
87
|
+
## Exact Effects
|
|
88
|
+
|
|
89
|
+
The receipt and replay carry every affected primary key and bounded before/
|
|
90
|
+
after digest. Kept-out fields are never fetched merely to improve audit detail.
|
|
91
|
+
The source receipt and mutation share one transaction in `source_db` mode.
|
|
92
|
+
`runner_ledger` mode retains the documented post-source-commit ambiguity and
|
|
93
|
+
uses `reconciliation_required`; it never retries an ambiguous batch.
|
|
94
|
+
|
|
95
|
+
## Operation Rules
|
|
96
|
+
|
|
97
|
+
### Set UPDATE
|
|
98
|
+
|
|
99
|
+
- fixed literal predicate;
|
|
100
|
+
- fixed or scalar-argument patch with existing per-field bounds;
|
|
101
|
+
- exact version guard and monotonic version advance for every row;
|
|
102
|
+
- mandatory aggregate bound;
|
|
103
|
+
- one transaction and exact affected-row count.
|
|
104
|
+
|
|
105
|
+
### Set DELETE
|
|
106
|
+
|
|
107
|
+
- fixed literal predicate;
|
|
108
|
+
- exact version guard for every row;
|
|
109
|
+
- verified human approval;
|
|
110
|
+
- no write triggers or cascading foreign keys;
|
|
111
|
+
- bounded tombstones and exact identities.
|
|
112
|
+
|
|
113
|
+
Soft delete remains the preferred set operation because it is a guarded
|
|
114
|
+
UPDATE and can later be reversed safely.
|
|
115
|
+
|
|
116
|
+
### Batch INSERT
|
|
117
|
+
|
|
118
|
+
- one typed item array with `max_items` no greater than `MAX ROWS`;
|
|
119
|
+
- every candidate row shown in the proposal;
|
|
120
|
+
- trusted tenant injected by Runner;
|
|
121
|
+
- source UNIQUE/PRIMARY KEY dedup identity for every item;
|
|
122
|
+
- per-item bounds plus a mandatory aggregate bound;
|
|
123
|
+
- all rows and source receipts commit atomically or none do.
|
|
124
|
+
|
|
125
|
+
## Threat Cases And Fixtures
|
|
126
|
+
|
|
127
|
+
| Threat | Mitigation | Conformance fixture |
|
|
128
|
+
| --- | --- | --- |
|
|
129
|
+
| R1 selection abuse | literal typed predicate; no model predicate inputs | `bounded-set-r1-fixed-selection` |
|
|
130
|
+
| R2 misleading cap | row cap plus aggregate value bound; overflow rejects | `bounded-set-r2-count-value-cap` |
|
|
131
|
+
| R3 TOCTOU drift | frozen PK/version set; apply never broad-requeries | `bounded-set-r3-frozen-drift` |
|
|
132
|
+
| R4 partial application | one transaction; exact count; rollback on any member | `bounded-set-r4-atomic-rollback` |
|
|
133
|
+
| R5 audit collapse | every key and bounded before/after digest in receipt/replay | `bounded-set-r5-exact-receipt` |
|
|
134
|
+
| R6 DELETE cascades | hard DELETE preflight rejects cascades/write triggers | `bounded-set-r6-delete-side-effects` |
|
|
135
|
+
| R7 auto-approval amplification | human approval mandatory; policy mode rejected | `bounded-set-r7-human-approval` |
|
|
136
|
+
|
|
137
|
+
Each fixture must be exercised by canonical validation and runtime/adapter
|
|
138
|
+
tests. A fixture file that is never loaded by a test is not evidence.
|
|
139
|
+
|
|
140
|
+
## Crash And Receipt Matrix
|
|
141
|
+
|
|
142
|
+
| Outcome | `source_db` | `runner_ledger` |
|
|
143
|
+
| --- | --- | --- |
|
|
144
|
+
| before source BEGIN | no effect | durable intent, no effect |
|
|
145
|
+
| one member stale | complete rollback and conflict receipt | complete rollback and terminal conflict |
|
|
146
|
+
| process death before source commit | complete rollback | complete rollback; intent may be safely resolved as not committed |
|
|
147
|
+
| process death after source commit | source mutation and receipt prove outcome atomically | `reconciliation_required`; never automatic retry |
|
|
148
|
+
| retry after completed receipt | `already_applied` | `already_applied` from authoritative ledger |
|
|
149
|
+
|
|
150
|
+
No mode claims a distributed transaction across Runner's ledger and an external
|
|
151
|
+
source database.
|
|
152
|
+
|
|
153
|
+
## Release Gate
|
|
154
|
+
|
|
155
|
+
The feature remains unavailable until Postgres and MySQL live tests prove:
|
|
156
|
+
|
|
157
|
+
- cap+1 and aggregate overflow reject before proposal persistence;
|
|
158
|
+
- one stale member and injected failure leave every source row unchanged;
|
|
159
|
+
- lock order is deterministic;
|
|
160
|
+
- exact IDs/digests appear in receipts and replay;
|
|
161
|
+
- hard DELETE side effects and auto-approval are rejected;
|
|
162
|
+
- batch INSERT dedup and crash behavior are safe in both receipt modes;
|
|
163
|
+
- seeded 1, 10, and 100 row measurements are recorded as local evidence only.
|
|
164
|
+
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# RFC 006: Reviewed Reversible Change Sets
|
|
2
|
+
|
|
3
|
+
Status: implemented and verified for the prepared Runner 1.4 release line
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
An applied direct database write currently has evidence, approval, a guarded
|
|
8
|
+
writeback receipt, and replay, but no bounded compensating action. Correcting a
|
|
9
|
+
mistake requires an operator to author a new forward proposal manually.
|
|
10
|
+
|
|
11
|
+
Runner should be able to prepare a reviewed compensation without becoming a
|
|
12
|
+
database time-travel system or introducing an unreviewed rollback path.
|
|
13
|
+
|
|
14
|
+
## Safety boundary
|
|
15
|
+
|
|
16
|
+
Reversal is opt-in contract authority:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"reversibility": {
|
|
21
|
+
"mode": "reviewed_inverse"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The declaration is valid only for Runner-owned `direct_sql` writeback. It does
|
|
27
|
+
not apply to app handlers, Cloud workers, email, payments, or any other
|
|
28
|
+
external effect.
|
|
29
|
+
|
|
30
|
+
`synapsor-runner revert <proposal-id>` creates a new proposal. It never:
|
|
31
|
+
|
|
32
|
+
- mutates the source database;
|
|
33
|
+
- approves the proposal;
|
|
34
|
+
- bypasses tenant or operator identity checks;
|
|
35
|
+
- appears in the model-facing MCP tool list.
|
|
36
|
+
|
|
37
|
+
The new proposal must be independently approved and applied through the normal
|
|
38
|
+
trusted operator path.
|
|
39
|
+
|
|
40
|
+
## Protocol split
|
|
41
|
+
|
|
42
|
+
Published v1, v2, and v3 forward writeback jobs keep their existing meaning.
|
|
43
|
+
Reversible forward jobs carry an additive, explicit inverse-capture request.
|
|
44
|
+
The resulting execution receipt carries a bounded inverse descriptor only
|
|
45
|
+
after a successful, unambiguous source transaction.
|
|
46
|
+
|
|
47
|
+
Compensation is executed through a distinct normalized protocol v4 job. A v4
|
|
48
|
+
job contains:
|
|
49
|
+
|
|
50
|
+
- the exact source, tenant, and primary-key authority;
|
|
51
|
+
- a bounded, deterministically ordered member list;
|
|
52
|
+
- the original single-row or set cardinality;
|
|
53
|
+
- the state expected after the forward write;
|
|
54
|
+
- only the reviewed values to restore or remove;
|
|
55
|
+
- the original row and aggregate caps;
|
|
56
|
+
- the original approval role and quorum;
|
|
57
|
+
- lineage linking root, parent, and reverted proposals and the forward receipt;
|
|
58
|
+
- a maximum lineage depth.
|
|
59
|
+
|
|
60
|
+
This prevents compensation semantics from being inferred from a legacy job.
|
|
61
|
+
|
|
62
|
+
## Operation semantics
|
|
63
|
+
|
|
64
|
+
### UPDATE and soft delete
|
|
65
|
+
|
|
66
|
+
The inverse restores only previously reviewed writable values. The row must
|
|
67
|
+
still match the exact reviewed state left by the forward write. A monotonic
|
|
68
|
+
version column advances again during compensation; it is never decremented.
|
|
69
|
+
Any intervening write fails closed.
|
|
70
|
+
|
|
71
|
+
A soft delete is an UPDATE of a reviewed status or deletion marker and follows
|
|
72
|
+
these same rules.
|
|
73
|
+
|
|
74
|
+
### INSERT
|
|
75
|
+
|
|
76
|
+
The inverse deletes only the exact Runner-created identity. The current row
|
|
77
|
+
must still match the allowlisted values inserted by Runner. Trigger and foreign
|
|
78
|
+
key safety is rechecked immediately before deletion. A new dependent row or a
|
|
79
|
+
changed value blocks compensation.
|
|
80
|
+
|
|
81
|
+
Because this delete removes a row whose complete Runner-supplied values are
|
|
82
|
+
known, its own inverse may reinsert that exact row. It cannot infer or restore
|
|
83
|
+
unreviewed database-generated or trigger-generated state.
|
|
84
|
+
|
|
85
|
+
### Hard DELETE
|
|
86
|
+
|
|
87
|
+
A general hard DELETE records bounded reviewed before-state evidence but is
|
|
88
|
+
not automatically restorable. Generated identities, hidden required columns,
|
|
89
|
+
cascaded children, and trigger side effects cannot be reconstructed safely.
|
|
90
|
+
The receipt marks the inverse unavailable with specific reason codes and the
|
|
91
|
+
CLI recommends soft delete or an app-owned compensation capability.
|
|
92
|
+
|
|
93
|
+
## Bounded sets
|
|
94
|
+
|
|
95
|
+
Set compensation uses exactly the original frozen identities. It cannot widen
|
|
96
|
+
the predicate or increase the original row/value caps. Every member is locked
|
|
97
|
+
in deterministic primary-key order and checked before any mutation. One stale
|
|
98
|
+
member rolls back the entire transaction.
|
|
99
|
+
|
|
100
|
+
The inverse descriptor is bounded to 100 members and 256 scalar fields per
|
|
101
|
+
member, matching the public protocol hard ceilings.
|
|
102
|
+
|
|
103
|
+
## Receipt authority and crash behavior
|
|
104
|
+
|
|
105
|
+
With source-database receipt authority, mutation and source receipt remain in
|
|
106
|
+
one transaction. The inverse descriptor is deterministic from the immutable
|
|
107
|
+
job plus the state verified in that transaction, so an idempotent retry can
|
|
108
|
+
reproduce it without rereading kept-out columns.
|
|
109
|
+
|
|
110
|
+
With Runner-ledger authority, the existing cross-database crash window remains.
|
|
111
|
+
An ambiguous forward or compensation outcome enters
|
|
112
|
+
`reconciliation_required`. Runner does not generate or apply a revert until an
|
|
113
|
+
operator reconciles the original outcome and an applied receipt with an
|
|
114
|
+
available inverse exists.
|
|
115
|
+
|
|
116
|
+
## Lineage
|
|
117
|
+
|
|
118
|
+
Every compensation proposal records:
|
|
119
|
+
|
|
120
|
+
- `root_proposal_id`;
|
|
121
|
+
- `parent_proposal_id`;
|
|
122
|
+
- `reverts_proposal_id`;
|
|
123
|
+
- `forward_receipt_hash`;
|
|
124
|
+
- `depth`.
|
|
125
|
+
|
|
126
|
+
Depth is capped at 16. The same applied receipt may have only one active or
|
|
127
|
+
completed compensation child. To undo a compensation, the operator reverts the
|
|
128
|
+
child proposal, creating a linear audited chain instead of a cycle.
|
|
129
|
+
|
|
130
|
+
## Data minimization
|
|
131
|
+
|
|
132
|
+
Inverse capture may retain only:
|
|
133
|
+
|
|
134
|
+
- fixed primary-key and trusted tenant identity;
|
|
135
|
+
- conflict/version metadata;
|
|
136
|
+
- fields in the reviewed write allowlist;
|
|
137
|
+
- Runner-supplied deterministic deduplication fields needed to identify an
|
|
138
|
+
inserted row.
|
|
139
|
+
|
|
140
|
+
Visible read fields that were not writable and all kept-out fields are excluded.
|
|
141
|
+
Reversibility is rejected when the safe inverse cannot be represented with that
|
|
142
|
+
bounded data.
|
|
143
|
+
|
|
144
|
+
## Explicit non-goals
|
|
145
|
+
|
|
146
|
+
- point-in-time recovery or WAL replacement;
|
|
147
|
+
- automatic rollback;
|
|
148
|
+
- model-facing revert, approve, apply, or receipt tools;
|
|
149
|
+
- restoration of arbitrary hard deletes;
|
|
150
|
+
- compensation of app-owned executors or external effects;
|
|
151
|
+
- cross-table, cross-database, or unbounded compensation;
|
|
152
|
+
- weakening the existing optimistic concurrency and receipt-authority model.
|
|
@@ -112,7 +112,13 @@ not print database URLs or create the schema.
|
|
|
112
112
|
"read_url_env": "BILLING_POSTGRES_READ_URL",
|
|
113
113
|
"write_url_env": "BILLING_POSTGRES_WRITE_URL",
|
|
114
114
|
"read_only": false,
|
|
115
|
-
"statement_timeout_ms": 3000
|
|
115
|
+
"statement_timeout_ms": 3000,
|
|
116
|
+
"receipts": {
|
|
117
|
+
"authority": "source_db",
|
|
118
|
+
"provisioning": "precreated",
|
|
119
|
+
"schema": "synapsor",
|
|
120
|
+
"table": "writeback_receipts"
|
|
121
|
+
}
|
|
116
122
|
}
|
|
117
123
|
}
|
|
118
124
|
}
|
|
@@ -121,8 +127,13 @@ not print database URLs or create the schema.
|
|
|
121
127
|
`engine` is `postgres` or `mysql`. `read_url_env` is required. Use a
|
|
122
128
|
least-privilege read credential. `write_url_env` is optional unless direct SQL
|
|
123
129
|
writeback must apply; it should name a separate restricted writer. `read_only:
|
|
124
|
-
true` forbids direct SQL writeback. `statement_timeout_ms` is
|
|
125
|
-
timeout
|
|
130
|
+
true` forbids direct SQL writeback. `statement_timeout_ms` is an
|
|
131
|
+
operator-controlled positive timeout used for reads and direct SQL writeback.
|
|
132
|
+
PostgreSQL applies it as transaction-local `statement_timeout` and
|
|
133
|
+
`lock_timeout`. MySQL applies it to read/preflight execution and rounds it up
|
|
134
|
+
to whole seconds for `innodb_lock_wait_timeout`; MySQL does not provide the
|
|
135
|
+
same general DML statement-timeout guarantee as PostgreSQL. `ssl` carries
|
|
136
|
+
adapter-specific reviewed SSL options when used.
|
|
126
137
|
|
|
127
138
|
A contract's `SOURCE billing_postgres` must exactly match a `sources` key.
|
|
128
139
|
|
|
@@ -131,8 +142,31 @@ Long-running servers reuse native driver pools. Optional `pool` keys are
|
|
|
131
142
|
`idle_timeout_ms` (30000), `queue_timeout_ms` (5000), and `queue_limit`
|
|
132
143
|
(default `max(10, max_connections * 4)`). Queue overflow returns
|
|
133
144
|
`SOURCE_POOL_QUEUE_FULL`; acquisition timeout returns `SOURCE_POOL_TIMEOUT`.
|
|
145
|
+
With result envelope v2, these conditions and recognized transient driver
|
|
146
|
+
connection failures are model-facing `TEMPORARILY_UNAVAILABLE` errors with
|
|
147
|
+
`retryable: true` and a bounded `retry_after_ms`. Operational logs retain only
|
|
148
|
+
a normalized safe runtime code, not the driver message, host, or credentials.
|
|
134
149
|
One-shot CLI commands close their pools.
|
|
135
150
|
|
|
151
|
+
### Source receipts
|
|
152
|
+
|
|
153
|
+
`sources.<name>.receipts.authority` is `source_db` or `runner_ledger`.
|
|
154
|
+
|
|
155
|
+
- `source_db` requires `provisioning: "precreated"` or `"auto_migrate"`.
|
|
156
|
+
Optional fixed `schema` and `table` identifiers select the receipt table.
|
|
157
|
+
The source mutation and receipt share one transaction.
|
|
158
|
+
- `runner_ledger` forbids `provisioning`, `schema`, and `table`. It creates no
|
|
159
|
+
source receipt table. Local SQLite is permitted for one process;
|
|
160
|
+
networked/multi-Runner use requires authoritative shared Postgres
|
|
161
|
+
`runtime_store` and rejects mirror mode.
|
|
162
|
+
|
|
163
|
+
Existing configs without `receipts` retain the compatibility source-receipt
|
|
164
|
+
behavior. New onboarding asks explicitly. Runner-ledger UPDATE requires exact
|
|
165
|
+
version advancement; INSERT requires source-enforced deduplication; DELETE
|
|
166
|
+
requires an exact version guard. Ambiguous post-commit outcomes stop at
|
|
167
|
+
`reconciliation_required`. See
|
|
168
|
+
[Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md).
|
|
169
|
+
|
|
136
170
|
## Trusted context
|
|
137
171
|
|
|
138
172
|
```json
|
|
@@ -227,6 +261,39 @@ fields are documented in the JSON Schema and
|
|
|
227
261
|
lookup, visible fields, evidence, patch allowlist, bounds/transitions, conflict
|
|
228
262
|
guard, approval, and writeback mode.
|
|
229
263
|
|
|
264
|
+
## Bounded set operation fields
|
|
265
|
+
|
|
266
|
+
A set operation is portable reviewed authority, so it can arrive from a
|
|
267
|
+
contract or the equivalent embedded capability:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"operation": {
|
|
272
|
+
"kind": "update",
|
|
273
|
+
"cardinality": "set",
|
|
274
|
+
"selection": {
|
|
275
|
+
"all": [{ "column": "status", "operator": "eq", "value": "overdue" }]
|
|
276
|
+
},
|
|
277
|
+
"max_rows": 10,
|
|
278
|
+
"aggregate_bounds": [
|
|
279
|
+
{ "column": "balance_cents", "measure": "before", "maximum": 50000 }
|
|
280
|
+
],
|
|
281
|
+
"version_advance": { "column": "version", "strategy": "integer_increment" }
|
|
282
|
+
},
|
|
283
|
+
"approval": { "mode": "human", "required_role": "billing_reviewer" },
|
|
284
|
+
"writeback": { "mode": "direct_sql" }
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Set UPDATE/DELETE requires one through eight fixed equality terms in
|
|
289
|
+
`selection.all`; the model cannot add or override them. Every set requires
|
|
290
|
+
`max_rows` from 1 through 100 and one through eight aggregate bounds. Set
|
|
291
|
+
UPDATE requires integer version advancement. Batch INSERT instead declares
|
|
292
|
+
`operation.batch.items_from_arg` pointing to a bounded `object_array` argument
|
|
293
|
+
and item-field dedup components. All forms require human/operator approval and
|
|
294
|
+
direct SQL writeback in 1.3. See [Bounded Set
|
|
295
|
+
Writeback](bounded-set-writeback.md).
|
|
296
|
+
|
|
230
297
|
## Executors
|
|
231
298
|
|
|
232
299
|
```json
|
|
@@ -247,7 +314,10 @@ guard, approval, and writeback mode.
|
|
|
247
314
|
}
|
|
248
315
|
```
|
|
249
316
|
|
|
250
|
-
Types are `sql_update`, `http_handler`, and `command_handler`.
|
|
317
|
+
Types are `sql_update`, `http_handler`, and `command_handler`. The legacy
|
|
318
|
+
`sql_update` executor identifier now dispatches the reviewed native operation
|
|
319
|
+
(`insert`, `update`, or `delete`) and remains named for config compatibility.
|
|
320
|
+
HTTP handlers use
|
|
251
321
|
`url_env`, optional `POST|PUT|PATCH`, bearer auth, signing secret, and timeout.
|
|
252
322
|
Command handlers use `command_env` and timeout. Secrets stay in the environment.
|
|
253
323
|
See [Writeback Executors](writeback-executors.md).
|
|
@@ -382,9 +452,10 @@ capability permissions, and trusted session metadata.
|
|
|
382
452
|
|
|
383
453
|
## Direct SQL readiness
|
|
384
454
|
|
|
385
|
-
|
|
386
|
-
needs target-table SELECT
|
|
387
|
-
SELECT
|
|
455
|
+
For `source_db` + `precreated`, an administrator applies `writeback migration`
|
|
456
|
+
once. The steady-state writer needs target-table `SELECT` and only the reviewed
|
|
457
|
+
operation DML plus receipt-table `SELECT`/`INSERT`/`UPDATE`; it does not need
|
|
458
|
+
schema `CREATE`.
|
|
388
459
|
|
|
389
460
|
```bash
|
|
390
461
|
synapsor-runner writeback migration --engine postgres --schema synapsor
|
|
@@ -393,5 +464,8 @@ synapsor-runner writeback grants --engine postgres \
|
|
|
393
464
|
synapsor-runner doctor --config ./synapsor.runner.json --check-writeback
|
|
394
465
|
```
|
|
395
466
|
|
|
396
|
-
|
|
397
|
-
|
|
467
|
+
`source_db` + `auto_migrate` runs that fixed migration idempotently and needs
|
|
468
|
+
bounded `CREATE`. `runner_ledger` skips source receipt DDL/DML and validates its
|
|
469
|
+
authoritative ledger topology. Doctor uses rollback-only receipt and target
|
|
470
|
+
checks and does not mutate business rows. See
|
|
471
|
+
[Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md).
|
|
@@ -89,7 +89,8 @@ worker termination during an open write transaction rolls back and recovers
|
|
|
89
89
|
worker termination after commit recovers as already-applied
|
|
90
90
|
source-down, read-only-ledger, and timeout readiness failures recover without restart
|
|
91
91
|
shared dead letters requeue or discard with receipts and events preserved
|
|
92
|
-
Postgres and MySQL pool queues fail fast at configured bounds
|
|
92
|
+
Postgres and MySQL pool queues fail fast at configured bounds with retry hints
|
|
93
|
+
shared runtime-store batch apply preserves one authoritative bridge and durable receipts
|
|
93
94
|
backup digest and clean restore match
|
|
94
95
|
retention archives before delete and preserves active proposals
|
|
95
96
|
```
|
|
@@ -20,6 +20,13 @@ trusted context, evidence handles, query audit, local inspection, and
|
|
|
20
20
|
proposal-first writes. Proposal workflows add full replay across evidence,
|
|
21
21
|
approval, writeback receipts, and events.
|
|
22
22
|
|
|
23
|
+
Prompt instructions and application validation are separate layers. Prompts
|
|
24
|
+
can guide behavior but cannot supply authorization. A fixed, parameterized
|
|
25
|
+
application tool can be a sound boundary for a small system; Runner adds a
|
|
26
|
+
portable reviewed contract and a consistent proposal, approval, receipt,
|
|
27
|
+
replay, and compensation lifecycle. See [Why Synapsor Over Prompt And
|
|
28
|
+
Application Guardrails](why-synapsor-vs-app-guardrails.md).
|
|
29
|
+
|
|
23
30
|
The model-facing MCP server exposes reviewed semantic tools such as
|
|
24
31
|
`billing.inspect_invoice` and `billing.propose_late_fee_waiver`.
|
|
25
32
|
|
|
@@ -67,17 +74,35 @@ outside the model-facing MCP server and verifies:
|
|
|
67
74
|
- allowed mutable columns;
|
|
68
75
|
- conflict/version guard;
|
|
69
76
|
- idempotency key;
|
|
77
|
+
- operation-specific version or source-unique deduplication guard;
|
|
70
78
|
- job expiry;
|
|
71
|
-
- exactly one
|
|
79
|
+
- exactly one reviewed row or every member of one bounded frozen set.
|
|
72
80
|
|
|
73
81
|
If any authority check cannot be verified, the write fails closed.
|
|
74
82
|
|
|
75
83
|
For direct SQL writeback, the writer connection is the env var named by the
|
|
76
|
-
source `write_url_env` in `synapsor.runner.json`.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
|
|
84
|
+
source `write_url_env` in `synapsor.runner.json`. With `source_db` receipt
|
|
85
|
+
authority, the source mutation and receipt commit atomically; the receipt table
|
|
86
|
+
can be administrator-precreated or explicitly auto-migrated. With
|
|
87
|
+
`runner_ledger` authority, Runner creates no source receipt table, but a crash
|
|
88
|
+
after source commit and before ledger completion can require verified operator
|
|
89
|
+
reconciliation. It is not distributed exactly-once. See
|
|
90
|
+
[Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md).
|
|
91
|
+
|
|
92
|
+
Bounded-set direct writeback additionally requires a contract-fixed predicate
|
|
93
|
+
or complete reviewed item list, `MAX ROWS` plus aggregate bounds,
|
|
94
|
+
human/operator approval, exact frozen identities and versions, deterministic
|
|
95
|
+
locks, one atomic source transaction, and per-member receipt digests. The
|
|
96
|
+
model cannot supply the predicate or cap. See [Bounded Set
|
|
97
|
+
Writeback](bounded-set-writeback.md).
|
|
98
|
+
|
|
99
|
+
When a direct SQL capability opts into reviewed reversibility, an applied
|
|
100
|
+
receipt may carry a bounded inverse containing only trusted identity, version,
|
|
101
|
+
and reviewed writable values. `revert` is operator-only and creates a new
|
|
102
|
+
proposal; it never mutates or approves. Compensation rechecks the exact forward
|
|
103
|
+
result under the trusted tenant and uses the normal approval, receipt,
|
|
104
|
+
reconciliation, and replay boundaries. See [Reviewed Reversible Change
|
|
105
|
+
Sets](reversible-change-sets.md).
|
|
81
106
|
|
|
82
107
|
When a capability uses an `http_handler` or `command_handler` executor, the
|
|
83
108
|
same approval boundary applies. The runner sends a structured proposal/job
|
|
@@ -96,6 +121,8 @@ approve/reject actions. It does not expose raw SQL, database URLs, write
|
|
|
96
121
|
credentials, approval tools, commit tools, or controls that widen reviewed
|
|
97
122
|
tables/columns.
|
|
98
123
|
|
|
99
|
-
Synapsor Runner supports reviewed single-row
|
|
100
|
-
|
|
101
|
-
|
|
124
|
+
Synapsor Runner supports reviewed single-row CRUD and the narrowly bounded set
|
|
125
|
+
path documented above. It does not support arbitrary SQL, DDL, UPSERT,
|
|
126
|
+
model-generated predicates, unbounded sets, or cross-table direct writeback.
|
|
127
|
+
Hard DELETE fails closed when cascades, write triggers, or required metadata
|
|
128
|
+
visibility prevent a bounded-effect proof.
|