@synapsor/runner 1.1.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +92 -1
  2. package/README.md +26 -7
  3. package/THREAT_MODEL.md +7 -4
  4. package/dist/cli.d.ts +5 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/local-ui.d.ts.map +1 -1
  7. package/dist/runner.mjs +8060 -2615
  8. package/docs/README.md +19 -3
  9. package/docs/capability-authoring.md +20 -8
  10. package/docs/conformance.md +12 -0
  11. package/docs/current-scope.md +12 -4
  12. package/docs/doctor.md +21 -7
  13. package/docs/dsl-reference.md +91 -5
  14. package/docs/getting-started-own-database.md +26 -3
  15. package/docs/guarded-crud-writeback.md +218 -0
  16. package/docs/limitations.md +30 -9
  17. package/docs/oss-vs-cloud.md +1 -1
  18. package/docs/production.md +52 -20
  19. package/docs/release-notes.md +82 -2
  20. package/docs/release-policy.md +1 -1
  21. package/docs/result-envelope-v2.md +20 -6
  22. package/docs/result-envelope-v4.md +47 -0
  23. package/docs/reversible-change-sets.md +151 -0
  24. package/docs/rfcs/004-guarded-crud-receipt-authority.md +165 -0
  25. package/docs/rfcs/005-bounded-set-writeback.md +164 -0
  26. package/docs/rfcs/006-reviewed-reversible-change-sets.md +152 -0
  27. package/docs/runner-config-reference.md +83 -9
  28. package/docs/running-a-runner-fleet.md +2 -1
  29. package/docs/security-boundary.md +29 -9
  30. package/docs/writeback-executors.md +12 -11
  31. package/examples/runner-fleet/seed/mysql.sql +47 -0
  32. package/examples/runner-fleet/seed/postgres.sql +48 -0
  33. package/examples/support-plan-credit/README.md +31 -0
  34. package/examples/support-plan-credit/contract.synapsor.sql +26 -0
  35. package/examples/support-plan-credit/expected-output/tools-preview.txt +1 -0
  36. package/examples/support-plan-credit/seed/001_seed.sql +14 -1
  37. package/examples/support-plan-credit/synapsor.contract.json +101 -1
  38. package/examples/support-plan-credit/synapsor.runner.json +7 -1
  39. package/fixtures/protocol/MANIFEST.json +131 -1
  40. package/fixtures/protocol/change-set.bounded-update.v3.json +57 -0
  41. package/fixtures/protocol/change-set.delete.v2.json +31 -0
  42. package/fixtures/protocol/change-set.insert.v2.json +36 -0
  43. package/fixtures/protocol/change-set.update.v2.json +32 -0
  44. package/fixtures/protocol/compensation-change-set.update.v1.json +40 -0
  45. package/fixtures/protocol/execution-receipt.bounded-update-applied.v3.json +39 -0
  46. package/fixtures/protocol/execution-receipt.compensation-update-applied.v4.json +37 -0
  47. package/fixtures/protocol/execution-receipt.delete-applied.v2.json +25 -0
  48. package/fixtures/protocol/execution-receipt.insert-applied.v2.json +24 -0
  49. package/fixtures/protocol/execution-receipt.reconciliation-required.v2.json +25 -0
  50. package/fixtures/protocol/execution-receipt.update-applied.v2.json +25 -0
  51. package/fixtures/protocol/writeback-job.bounded-update.v3.json +43 -0
  52. package/fixtures/protocol/writeback-job.compensation-update.v4.json +34 -0
  53. package/fixtures/protocol/writeback-job.delete.v2.json +22 -0
  54. package/fixtures/protocol/writeback-job.insert.v2.json +28 -0
  55. package/fixtures/protocol/writeback-job.update.v2.json +24 -0
  56. package/package.json +1 -1
  57. package/schemas/change-set.v2.schema.json +245 -0
  58. package/schemas/change-set.v3.schema.json +112 -0
  59. package/schemas/compensation-change-set.v1.schema.json +32 -0
  60. package/schemas/execution-receipt.v2.schema.json +106 -0
  61. package/schemas/execution-receipt.v3.schema.json +40 -0
  62. package/schemas/execution-receipt.v4.schema.json +22 -0
  63. package/schemas/inverse-descriptor.v1.schema.json +46 -0
  64. package/schemas/synapsor.runner.schema.json +132 -2
  65. package/schemas/writeback-job.v2.schema.json +238 -0
  66. package/schemas/writeback-job.v3.schema.json +53 -0
  67. package/schemas/writeback-job.v4.schema.json +17 -0
@@ -1,7 +1,9 @@
1
1
  # Limitations
2
2
 
3
- Synapsor Runner is intentionally narrow. Version 1.1 adds a bounded small-fleet
4
- shape; it does not claim Synapsor Cloud scale or an enterprise SLA.
3
+ Synapsor Runner is intentionally narrow. Version 1.4 adds opt-in reviewed
4
+ compensation on top of guarded bounded-set writeback, single-row CRUD, and
5
+ explicit receipt authority; it does not claim Synapsor Cloud scale or an
6
+ enterprise SLA.
5
7
 
6
8
  ## Supported
7
9
 
@@ -20,8 +22,20 @@ shape; it does not claim Synapsor Cloud scale or an enterprise SLA.
20
22
  - `synapsor.change-set.v1`
21
23
  - `synapsor.writeback-job.v1`
22
24
  - `synapsor.execution-receipt.v1`
25
+ - backward-compatible operation-aware v2 change sets, jobs, and receipts
26
+ - bounded-set v3 change sets, jobs, and receipts
27
+ - compensation change sets and protocol-v4 jobs/receipts with bounded inverse
28
+ descriptors
23
29
  - `synapsor.runner-registration.v1`
24
- - Guarded single-row `UPDATE` for Postgres and MySQL.
30
+ - Guarded single-row `INSERT`, `UPDATE`, and `DELETE` for Postgres and MySQL.
31
+ - Fixed-predicate set `UPDATE`/`DELETE` and exact-review batch `INSERT` with
32
+ mandatory row/value caps, a hard 100-row ceiling, human approval, frozen
33
+ members, atomic apply, and exact receipts.
34
+ - Opt-in reviewed compensation for direct SQL UPDATE, INSERT, soft-delete, and
35
+ exact frozen sets. Revert is a new operator proposal with independent
36
+ approval and a fresh conflict guard.
37
+ - Atomic source receipts with precreated or auto-migrated tables, or
38
+ zero-source-schema Runner-ledger receipts with explicit reconciliation.
25
39
  - App/API handler writeback through approved `http_handler` executors.
26
40
  - Local script writeback through approved `command_handler` executors.
27
41
  - Primary-key guard.
@@ -49,17 +63,19 @@ truth for the model-facing tools.
49
63
  - Arbitrary SQL.
50
64
  - Model-generated SQL.
51
65
  - DDL.
52
- - INSERT.
53
- - DELETE.
54
66
  - UPSERT.
55
- - Multi-row UPDATE.
67
+ - Model-generated/free-form set predicates or dynamic identifiers.
68
+ - Unbounded set writes or more than 100 reviewed members.
69
+ - Policy auto-approval for bounded sets.
56
70
  - Stored procedures.
57
71
  - Cross-database transactions.
58
72
  - Physical branching of Postgres/MySQL.
59
73
  - Full Synapsor workflow/DAG execution.
60
74
  - `CREATE AGENT WORKFLOW` or hosted Synapsor SQL generation.
61
75
  - Auto-merge or settlement policy semantics.
62
- - Automatic rollback of external database writes.
76
+ - Automatic rollback, database time travel, or model-facing revert.
77
+ - Inferred compensation for app-owned handlers or external effects.
78
+ - General restoration of hard-deleted rows, cascades, or trigger side effects.
63
79
  - Model-callable approval or commit tools.
64
80
  - Generic MCP firewall behavior.
65
81
  - Prompt-injection prevention.
@@ -92,8 +108,9 @@ not a hosted central evidence service, organization RBAC/SSO, compliance
92
108
  retention system, or unbounded search engine. Each bridge operation serializes
93
109
  through an advisory lock and fails above configured `max_entries`.
94
110
 
95
- Only homogeneous 1.1 fleet operation is currently verified. Mixed 1.0/1.1
96
- rolling operation is not claimed. See [Running A Small Runner
111
+ Only homogeneous 1.4 fleet operation is claimed for protocol-v4 compensation
112
+ jobs. Mixed-minor v3/v4 rolling compensation is not claimed.
113
+ See [Running A Small Runner
97
114
  Fleet](running-a-runner-fleet.md).
98
115
 
99
116
  Use this wording:
@@ -108,3 +125,7 @@ Do not describe external approval as merge.
108
125
  ## Weak Conflict Guards
109
126
 
110
127
  A version/timestamp column is the preferred conflict guard. A weak row-hash guard can be acknowledged for local/dev use, but it should not be presented as equivalent to a durable version column.
128
+
129
+ Runner-ledger UPDATE and DELETE require an exact guard; UPDATE must advance it
130
+ inside the source transaction. INSERT requires a reviewed source-unique dedup
131
+ identity. See [Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md).
@@ -21,7 +21,7 @@ and investigation surfaces for enabled design-partner deployments.
21
21
  | Capabilities | Local semantic MCP tools | Registry, version history, and capability inspection |
22
22
  | Evidence and replay | Local SQLite ledger by default; optional shared Postgres runtime store | Shared activity and evidence surfaces where enabled |
23
23
  | Approval | Local CLI or localhost UI | Team approval surfaces where enabled |
24
- | Writeback | Guarded one-row update or app-owned executor | Cloud-linked jobs with local execution; managed production orchestration is future work |
24
+ | Writeback | Guarded one-row CRUD, fixed/frozen bounded sets, or app-owned executor | Cloud-linked jobs with local execution; managed production orchestration is future work |
25
25
  | MCP risk audit | Static local audit | Organization-wide continuous audit is future work |
26
26
  | Identity | Local operator boundary | Workspace RBAC where configured; SAML and SCIM are future work |
27
27
  | Operations | Customer-operated single node or bounded small fleet | Managed fleet remains Cloud work; no enterprise SLA in the current beta |
@@ -10,7 +10,7 @@ MCP agent
10
10
  -> scoped Postgres/MySQL read
11
11
  -> evidence/query audit/proposal
12
12
  -> approval outside MCP
13
- -> guarded one-row update or app-owned executor
13
+ -> guarded one-row CRUD, bounded frozen set, or app-owned executor
14
14
  -> receipt/replay
15
15
  ```
16
16
 
@@ -58,7 +58,14 @@ Production-candidate OSS scope:
58
58
  - asymmetric RS256/ES256 session authentication, readiness probes, separately
59
59
  protected metrics, source pools, and fleet-wide rate limits;
60
60
  - distinct-reviewer approval quorum from the canonical contract;
61
- - direct guarded single-row `UPDATE` for simple approved edits;
61
+ - direct guarded single-row `INSERT`, `UPDATE`, and `DELETE` for approved
62
+ operations whose source constraints satisfy the operation-specific guards;
63
+ - fixed-predicate set `UPDATE`/`DELETE` and exact-review batch `INSERT`, with
64
+ human approval, mandatory row/value caps, a hard 100-row ceiling, frozen
65
+ members, atomic execution, and exact per-member receipts;
66
+ - opt-in reviewed compensation for direct SQL UPDATE, INSERT, soft-delete, and
67
+ exact frozen sets, using a separate operator proposal, fresh guards, and
68
+ protocol-v4 receipts;
62
69
  - app-owned `http_handler` or `command_handler` executors for richer approved
63
70
  business transactions;
64
71
  - stdio MCP and Streamable HTTP MCP.
@@ -66,8 +73,12 @@ Production-candidate OSS scope:
66
73
  Out of scope:
67
74
 
68
75
  - raw `execute_sql` or model-generated SQL;
69
- - generic direct `INSERT`, `DELETE`, `UPSERT`, DDL, or multi-row SQL writeback;
76
+ - direct `UPSERT`, DDL, model-generated predicates, unbounded set writes,
77
+ cross-table transactions, or INSERT/DELETE whose source constraints cannot
78
+ prove the reviewed effect;
70
79
  - physical branching of external Postgres/MySQL;
80
+ - automatic rollback/time travel, hard-delete restoration, and inferred
81
+ compensation for app-owned or external effects;
71
82
  - workflow DAGs, auto-merge/settlement, hosted team administration, SSO/SCIM,
72
83
  multi-region ledger replication, or compliance retention;
73
84
  - making prompt injection impossible.
@@ -85,11 +96,12 @@ Read credential:
85
96
 
86
97
  Write credential for direct `sql_update`:
87
98
 
88
- - can update only the allowed business columns;
99
+ - can use only the operation-specific business DML and reviewed columns;
89
100
  - cannot modify primary-key or tenant columns;
90
- - can `SELECT`/`INSERT`/`UPDATE` the administrator-created
91
- `synapsor_writeback_receipts` table;
92
- - does not need schema `CREATE` during doctor or apply;
101
+ - has source receipt-table `SELECT`/`INSERT`/`UPDATE` only when receipt
102
+ authority is `source_db`;
103
+ - needs schema `CREATE` only for explicitly selected `auto_migrate` receipt
104
+ provisioning;
93
105
  - is never exposed to MCP clients.
94
106
 
95
107
  Example config:
@@ -110,10 +122,17 @@ Example config:
110
122
  `write_url_env`. `SYNAPSOR_DATABASE_URL` is only a legacy fallback for direct
111
123
  worker flows that do not pass a local config.
112
124
 
113
- ## Receipt Table
125
+ Set `statement_timeout_ms` on each production source. PostgreSQL direct
126
+ writeback uses it for transaction-local statement and lock limits. MySQL uses
127
+ it for preflight execution and InnoDB lock waits; because MySQL does not apply
128
+ `max_execution_time` to general DML, keep bounded sets small and enforce
129
+ source-side operational query limits too.
114
130
 
115
- Direct SQL writeback stores idempotency receipts in the source database. Runner
116
- expects an administrator to create this table before steady-state operation:
131
+ ## Receipt Authority
132
+
133
+ Direct SQL writeback supports atomic `source_db` receipts and
134
+ zero-source-schema `runner_ledger` receipts. For source receipts, choose an
135
+ administrator-precreated table or explicit idempotent auto-migration:
117
136
 
118
137
  ```sql
119
138
  CREATE TABLE IF NOT EXISTS synapsor_writeback_receipts (...);
@@ -129,26 +148,36 @@ synapsor-runner doctor --config synapsor.runner.json --check-writeback
129
148
 
130
149
  For MySQL, replace `postgres` with `mysql`.
131
150
 
132
- Grant only receipt-table `SELECT`/`INSERT`/`UPDATE` and schema usage to the
133
- writer; schema `CREATE` is not required by doctor or apply. Use an app-owned
134
- executor when receipt storage belongs inside your application boundary.
151
+ Grant only receipt-table `SELECT`/`INSERT`/`UPDATE` and schema usage in
152
+ `precreated` mode. `auto_migrate` additionally needs bounded `CREATE`.
153
+ `runner_ledger` needs neither source receipt-table grants nor `CREATE`, but an
154
+ ambiguous crash after source commit requires operator reconciliation and is not
155
+ distributed exactly-once. See
156
+ [Guarded Single-Row CRUD Writeback](guarded-crud-writeback.md) for the complete
157
+ mode, operation, and privilege matrix.
135
158
 
136
159
  ## Direct Writeback Vs App-Owned Executor
137
160
 
138
- Use direct `sql_update` when the approved change is:
161
+ Use direct writeback when the approved change is either:
139
162
 
140
163
  ```text
141
- one existing row -> one allowed-column patch -> one guarded UPDATE
164
+ one reviewed row -> one guarded INSERT/UPDATE/DELETE -> one exact effect
165
+
166
+ or
167
+
168
+ one fixed reviewed rule/item list -> <= 100 frozen rows -> one atomic bounded set
142
169
  ```
143
170
 
144
171
  Use an app-owned executor when the change is richer:
145
172
 
146
- - insert a credit/refund/review row;
147
- - update more than one row;
173
+ - choose rows from a model-supplied predicate or exceed the reviewed cap;
148
174
  - touch more than one table;
149
175
  - emit an event or call another internal service;
150
176
  - enforce business logic that belongs in your app.
151
177
 
178
+ Bounded sets must satisfy every invariant in [Bounded Set
179
+ Writeback](bounded-set-writeback.md); otherwise they remain executor work.
180
+
152
181
  Handlers must re-check tenant/scope, expected version, idempotency, allowed
153
182
  business action, transaction boundaries, and safe errors. See
154
183
  [Writeback Executors](writeback-executors.md) and
@@ -336,9 +365,12 @@ synapsor-runner apply --all-approved --yes \
336
365
  ```
337
366
 
338
367
  Each proposal is independent: a stale-row conflict does not abort later jobs.
339
- The final summary reports applied, conflict, and skipped IDs. Re-running is
340
- idempotent through durable receipts. Do not schedule batch apply for a policy
341
- that has no reviewed aggregate limits.
368
+ In `runtime_store` mode, the batch holds one authoritative bridge while every
369
+ selected item applies, then syncs the resulting states, receipts, and events
370
+ back together. The final summary reports applied, conflict, and skipped IDs;
371
+ every skipped item includes a safe reason. Re-running is idempotent through
372
+ durable receipts. Do not schedule batch apply for a policy that has no reviewed
373
+ aggregate limits.
342
374
 
343
375
  Runner writes newline-delimited JSON events to stderr for model-facing tool
344
376
  rejections, operator decisions, and terminal writeback outcomes. These events
@@ -10,7 +10,87 @@ npx -y -p @synapsor/runner synapsor-runner demo --quick
10
10
  The OSS runner command is `synapsor-runner`. The `synapsor` command is reserved
11
11
  for the Synapsor Cloud CLI.
12
12
 
13
- ## 1.1.0 (prepared, not published)
13
+ ## 1.4.0 (prepared, not published)
14
+
15
+ ### Reviewed Reversible Change Sets
16
+
17
+ - Adds canonical and DSL opt-in reversibility for direct SQL operations with
18
+ human/operator approval and exact version/dedup guards.
19
+ - Records only bounded, allowlisted inverse data after an unambiguous apply.
20
+ - Adds operator-only `revert`, which creates a new independently reviewed
21
+ proposal and never writes, approves, or becomes model-facing.
22
+ - Proves UPDATE, INSERT, soft-delete, and exact bounded-set compensation on
23
+ PostgreSQL and MySQL, including stale-state refusal, atomic set rollback,
24
+ crash reconciliation, inverse redaction, receipts, and replay.
25
+ - Keeps hard DELETE restoration, app-owned handlers, payments, messages, and
26
+ other external effects outside Runner's automatic compensation claim.
27
+
28
+ Prepared package versions: `@synapsor/spec@1.4.0`,
29
+ `@synapsor/dsl@1.4.0`, and `@synapsor/runner@1.4.0`.
30
+
31
+ ## 1.3.0 (prepared, not published)
32
+
33
+ ### Bounded Set Writeback
34
+
35
+ - Adds fixed-predicate set UPDATE/DELETE and exact-review batch INSERT for
36
+ PostgreSQL and MySQL, capped at 100 rows.
37
+ - Requires mandatory row and aggregate-value bounds, a frozen exact target set,
38
+ integer version guards for set UPDATE, human/operator approval, atomic apply,
39
+ and per-member receipt/replay evidence.
40
+ - Rejects cap overflow instead of truncating, rolls back the full transaction
41
+ on any stale or failing member, and refuses hard set DELETE when hidden
42
+ triggers or widening cascades are present.
43
+ - Keeps model-generated predicates, policy auto-approval for sets, unbounded
44
+ batches, UPSERT, cross-table transactions, and external effects on the
45
+ app-owned executor path.
46
+ - Adds `corepack pnpm test:bounded-set`, which runs the safety matrix and local
47
+ 1/10/100-row measurements against disposable PostgreSQL and MySQL.
48
+
49
+ Prepared package versions: `@synapsor/spec@1.3.0`,
50
+ `@synapsor/dsl@1.3.0`, and `@synapsor/runner@1.3.0`.
51
+
52
+ ## 1.2.0 (prepared, not published)
53
+
54
+ ### Guarded CRUD And Receipt Authority
55
+
56
+ - Adds canonical and DSL operation semantics for guarded single-row INSERT,
57
+ UPDATE, and DELETE while preserving legacy UPDATE contracts.
58
+ - Adds atomic source receipts with precreated or auto-migrated tables and an
59
+ opt-in Runner-ledger mode that creates no source receipt table.
60
+ - Adds durable writeback intents and a fail-closed operator reconciliation
61
+ workflow for ambiguous ledger/source crash windows.
62
+ - Extends onboarding, doctor, preview, schema inspection, protocol v2,
63
+ Postgres/MySQL adapters, the support-plan-credit example, and disposable live
64
+ conformance tests.
65
+ - Keeps multi-row writes, UPSERT, DDL, cross-table work, and external effects
66
+ on the app-owned executor path.
67
+
68
+ Prepared package versions: `@synapsor/spec@1.2.0`,
69
+ `@synapsor/dsl@1.2.0`, and `@synapsor/runner@1.2.0`.
70
+
71
+ ## 1.1.2 (prepared, not published)
72
+
73
+ ### Retry And Shared Batch Correctness
74
+
75
+ - Makes transient source pool and recognized database saturation errors
76
+ consistently retryable with a bounded retry hint and safe normalized logs.
77
+ - Fixes `apply --all-approved` in shared `runtime_store` mode so every selected
78
+ proposal uses the same authoritative bridge and durable outcome ledger.
79
+
80
+ Prepared package version: `@synapsor/runner@1.1.2`. Canonical Spec and DSL stay
81
+ at `1.1.0`.
82
+
83
+ ## 1.1.1
84
+
85
+ ### Resource Read Authorization
86
+
87
+ - Reauthorizes local proposal, evidence, and replay resources against the
88
+ current trusted tenant and principal instead of treating opaque handles as
89
+ bearer authority.
90
+
91
+ Released package version: `@synapsor/runner@1.1.1`.
92
+
93
+ ## 1.1.0
14
94
 
15
95
  ### Bounded Small-Fleet Runtime
16
96
 
@@ -27,7 +107,7 @@ for the Synapsor Cloud CLI.
27
107
  - Adds [Running A Small Runner Fleet](running-a-runner-fleet.md) and the
28
108
  `corepack pnpm test:fleet` synthetic two-Runner verification.
29
109
 
30
- Prepared package versions: `@synapsor/spec@1.1.0`,
110
+ Released package versions: `@synapsor/spec@1.1.0`,
31
111
  `@synapsor/dsl@1.1.0`, and `@synapsor/runner@1.1.0`.
32
112
 
33
113
  ## 1.0.0
@@ -123,7 +123,7 @@ through the `1.x` line unless a release note marks a deprecation first:
123
123
 
124
124
  Stable does not promise production SLA, hosted Cloud features, compliance
125
125
  certification, physical Postgres/MySQL branching, generic SQL writeback,
126
- generic multi-row writes, or compatibility for undocumented local SQLite
126
+ free-form/unbounded set writes, or compatibility for undocumented local SQLite
127
127
  internals. Local store migrations may happen inside `1.x` and later minor
128
128
  versions, but documented CLI inspection commands should remain the supported way
129
129
  to read the store.
@@ -86,6 +86,7 @@ database.
86
86
  "approval_required": true,
87
87
  "writeback": {
88
88
  "mode": "direct_update",
89
+ "operation": "update",
89
90
  "applied": false
90
91
  },
91
92
  "next": "A human must approve outside this model-facing tool surface; nothing is committed yet."
@@ -101,12 +102,22 @@ database.
101
102
  }
102
103
  ```
103
104
 
104
- For app-owned executors, `proposal.writeback.mode` is `app_handler`.
105
+ For app-owned executors, `proposal.writeback.mode` is `app_handler`. Native
106
+ guarded proposals use `direct_insert`, `direct_update`, or `direct_delete`, and
107
+ `proposal.writeback.operation` is `insert`, `update`, or `delete`. Every
108
+ proposal result still reports `source_database_changed: false` until external
109
+ apply.
110
+
111
+ For bounded sets, the same model-facing v2 envelope reports the operation,
112
+ reviewed member count, row cap, aggregate values/maximums, set digest, and exact
113
+ allowlisted member diffs. Protocol v3 is used behind the envelope for the
114
+ frozen job and receipt; see [Result Envelope v3](result-envelope-v3.md).
105
115
 
106
116
  ## Error Result
107
117
 
108
- Model-facing errors are safe and stable. Raw driver details stay in local logs
109
- or ledger inspection, not in the MCP result.
118
+ Model-facing errors are safe and stable. Structured tool-rejection logs also
119
+ omit raw driver messages, hosts, and credentials; use operator-controlled
120
+ readiness and database diagnostics to investigate the underlying dependency.
110
121
 
111
122
  ```json
112
123
  {
@@ -119,7 +130,8 @@ or ledger inspection, not in the MCP result.
119
130
  "error": {
120
131
  "code": "TEMPORARILY_UNAVAILABLE",
121
132
  "message": "The database is temporarily unavailable. Retry later.",
122
- "retryable": true
133
+ "retryable": true,
134
+ "retry_after_ms": 1000
123
135
  },
124
136
  "evidence": null,
125
137
  "source_database_changed": false,
@@ -143,8 +155,10 @@ TEMPORARILY_UNAVAILABLE
143
155
  INTERNAL
144
156
  ```
145
157
 
146
- Current alpha implementation redacts raw connection and driver messages from v2
147
- MCP results. New `init` and `onboard db` configs write `result_format: 2` by
158
+ Runner redacts raw connection and driver messages from v2 MCP results and
159
+ structured operational logs. Recognized transient pool, PostgreSQL, MySQL, and
160
+ network failures include a bounded `retry_after_ms`; unrelated database errors
161
+ remain non-retryable. New `init` and `onboard db` configs write `result_format: 2` by
148
162
  default. Existing hand-written configs without `result_format` keep the legacy
149
163
  runtime default for compatibility; pass `--result-format v2` when serving an
150
164
  older config to force the v2 envelope, or `--result-format v1` for an older
@@ -0,0 +1,47 @@
1
+ # Compensation Protocol v4
2
+
3
+ Protocol v4 is used only for reviewed compensation. Existing v1 single-row,
4
+ v2 CRUD, and v3 bounded-set objects keep their meaning.
5
+
6
+ Public objects:
7
+
8
+ - `synapsor.compensation-change-set.v1`;
9
+ - `synapsor.inverse-descriptor.v1`;
10
+ - `synapsor.writeback-job.v4`;
11
+ - `synapsor.execution-receipt.v4`.
12
+
13
+ The compensation change set is a normal proposal with a new proposal ID,
14
+ principal, tenant scope, evidence, approval requirement, integrity hash, and a
15
+ link to the exact applied forward receipt. It does not authorize execution.
16
+
17
+ The inverse descriptor records:
18
+
19
+ - `availability` plus specific `reason_codes` when unavailable;
20
+ - `restore_update`, `remove_insert`, or `restore_insert`;
21
+ - single-row or exact-set cardinality;
22
+ - fixed source, table, tenant guard, and allowed columns;
23
+ - exact primary-key members, expected forward state, and restore values;
24
+ - original row/aggregate caps and integer version advancement;
25
+ - root/parent/reverted proposal lineage and bounded depth.
26
+
27
+ A v4 writeback job is created only after the compensation proposal is
28
+ independently approved. The adapter locks and validates every member before
29
+ mutation, applies in one source transaction, and emits a v4 receipt. A
30
+ successful receipt contains the compensation's own bounded inverse. A stale or
31
+ missing member returns conflict without a partial effect.
32
+
33
+ With Runner-ledger receipt authority, an unacknowledged commit or rollback
34
+ enters `reconciliation_required`; no inverse is synthesized until a verified
35
+ operator resolves the outcome.
36
+
37
+ Canonical JSON Schemas are under:
38
+
39
+ ```text
40
+ schemas/inverse-descriptor.v1.schema.json
41
+ schemas/compensation-change-set.v1.schema.json
42
+ schemas/writeback-job.v4.schema.json
43
+ schemas/execution-receipt.v4.schema.json
44
+ ```
45
+
46
+ See [Reviewed Reversible Change Sets](reversible-change-sets.md) for the
47
+ operator flow and supported operation matrix.
@@ -0,0 +1,151 @@
1
+ # Reviewed Reversible Change Sets
2
+
3
+ Synapsor Runner 1.4 can capture a bounded inverse for an opt-in direct database
4
+ write. This is **reviewed compensation**, not rollback or database time travel.
5
+
6
+ The operator flow is deliberately two separate approval loops:
7
+
8
+ ```text
9
+ forward proposal -> approval -> guarded apply -> applied receipt with inverse
10
+ |
11
+ v
12
+ operator runs revert -> new proposal -> independent approval -> guarded apply
13
+ ```
14
+
15
+ `synapsor-runner revert` never writes, approves, or bypasses a guard. It is an
16
+ operator CLI command and is not exposed as an MCP tool.
17
+
18
+ ## Authoring
19
+
20
+ Add `REVERSIBLE` only to a direct SQL proposal whose inverse Runner can prove:
21
+
22
+ ```sql
23
+ CREATE CAPABILITY billing.propose_plan_credit
24
+ USING CONTEXT trusted_operator
25
+ SOURCE billing_postgres
26
+ ON public.customers
27
+ PRIMARY KEY id
28
+ TENANT KEY tenant_id
29
+ CONFLICT GUARD version
30
+ LOOKUP customer_id BY id
31
+ ARG customer_id STRING REQUIRED MAX LENGTH 128
32
+ ARG amount_cents NUMBER REQUIRED MIN 1 MAX 2500
33
+ ALLOW READ id, tenant_id, plan_credit_cents, version
34
+ REQUIRE EVIDENCE
35
+ MAX ROWS 1
36
+ PROPOSE ACTION grant_plan_credit UPDATE
37
+ ALLOW WRITE plan_credit_cents
38
+ PATCH plan_credit_cents = ARG amount_cents
39
+ BOUND plan_credit_cents 0..2500
40
+ ADVANCE VERSION version USING INTEGER INCREMENT
41
+ APPROVAL ROLE support_reviewer
42
+ WRITEBACK DIRECT SQL
43
+ REVERSIBLE
44
+ END
45
+ ```
46
+
47
+ The canonical JSON equivalent is:
48
+
49
+ ```json
50
+ {
51
+ "proposal": {
52
+ "reversibility": { "mode": "reviewed_inverse" }
53
+ }
54
+ }
55
+ ```
56
+
57
+ Validation rejects `REVERSIBLE` when writeback uses an app handler or Cloud
58
+ worker, approval is policy-driven, or an UPDATE lacks exact integer version
59
+ advancement. INSERT also requires a deterministic primary-key dedup component.
60
+
61
+ ## Operator Flow
62
+
63
+ After an unambiguous forward apply:
64
+
65
+ ```bash
66
+ synapsor-runner revert <forward_proposal_id> \
67
+ --config ./synapsor.runner.json \
68
+ --store ./.synapsor/local.db \
69
+ --reason "Correct the reviewed credit"
70
+
71
+ synapsor-runner proposals show latest --details --store ./.synapsor/local.db
72
+ synapsor-runner proposals approve latest --yes --store ./.synapsor/local.db
73
+ synapsor-runner apply latest --config ./synapsor.runner.json --store ./.synapsor/local.db
74
+ synapsor-runner replay show latest --store ./.synapsor/local.db
75
+ ```
76
+
77
+ The compensation proposal inherits the original reviewer role and quorum. A
78
+ signed operator identity is required when configured. The source remains
79
+ unchanged until the compensation proposal is separately approved and applied.
80
+
81
+ ## Supported Inverses
82
+
83
+ | Forward operation | Reviewed compensation |
84
+ | --- | --- |
85
+ | Single-row UPDATE | Restores only allowlisted prior values after checking the exact state and version left by the forward write. The version advances again; it is never decremented. |
86
+ | Soft delete | Same as UPDATE when deletion is a reviewed status or timestamp patch. |
87
+ | Single-row INSERT | Deletes only the exact Runner-created identity after checking current reviewed state, tenant, triggers, and foreign-key effects. |
88
+ | Bounded set UPDATE | Restores exactly the original frozen members under the original count/value caps in one transaction. One stale member aborts all members. |
89
+ | Exact-review batch INSERT | Removes exactly the inserted member identities, atomically, after the same safety preflight. |
90
+ | Hard DELETE | Not generally restorable. The receipt reports specific unavailable reason codes instead of claiming a safe inverse. |
91
+
92
+ Kept-out and non-writable fields are never captured just to make compensation
93
+ possible. Each successful compensation captures its own bounded inverse, so an
94
+ operator may propose a revert of the compensation. Lineage is linear, duplicate
95
+ children are rejected, and traversal is capped at 16 proposals.
96
+
97
+ ## Fail-Closed Cases
98
+
99
+ Runner refuses to create or apply compensation when:
100
+
101
+ - the forward outcome is missing, failed, or requires reconciliation;
102
+ - the applied receipt has no available inverse;
103
+ - another active compensation already targets that receipt;
104
+ - the tenant or operator identity does not match trusted authority;
105
+ - the row changed after the forward write;
106
+ - an inserted row is missing or has changed;
107
+ - a new trigger, foreign-key dependent, or widening cascade prevents a bounded
108
+ effect proof;
109
+ - any member of a bounded set is stale or missing;
110
+ - lineage is invalid, cyclic, or beyond the depth limit.
111
+
112
+ With `runner_ledger` receipt authority, a crash after source commit but before
113
+ ledger completion remains ambiguous. Forward and compensation writes enter
114
+ `reconciliation_required`; Runner does not call them reverted or retry them
115
+ automatically. Reconcile the outcome first through the verified operator
116
+ workflow.
117
+
118
+ ## Database Metadata Privileges
119
+
120
+ Postgres uses catalog visibility available to the configured writer for
121
+ trigger and foreign-key preflight.
122
+
123
+ MySQL compensation that may delete a row, including reversal of INSERT,
124
+ requires enough metadata visibility to prove no hidden widening effects:
125
+
126
+ - scoped `TRIGGER` visibility on the target table;
127
+ - global `PROCESS` visibility for incoming InnoDB foreign-key metadata.
128
+
129
+ If those privileges are not acceptable, use a reversible soft-delete UPDATE or
130
+ an explicitly reviewed app-owned compensation capability. Runner fails closed.
131
+
132
+ ## App-Owned Executors
133
+
134
+ Runner does not infer compensation for `http_handler`, `command_handler`,
135
+ payments, messages, or other external effects. The application must expose a
136
+ separate reviewed compensation capability and enforce its own tenant, version,
137
+ idempotency, and transaction rules. A handler returning a receipt does not make
138
+ its side effect Runner-reversible.
139
+
140
+ ## Verification
141
+
142
+ The disposable PostgreSQL/MySQL gate proves UPDATE, INSERT, soft-delete, exact
143
+ bounded-set compensation, independent approval, stale-state refusal,
144
+ hard-delete unavailability, inverse redaction, receipts, and replay:
145
+
146
+ ```bash
147
+ corepack pnpm test:reversible
148
+ ```
149
+
150
+ See [RFC 006](rfcs/006-reviewed-reversible-change-sets.md) for the normative
151
+ safety design and [Current Limitations](limitations.md) for the wider boundary.