@synapsor/runner 1.5.4 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -2
- package/README.md +131 -124
- package/dist/authoring.mjs +405 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +6 -1
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +17206 -12169
- package/dist/runtime.mjs +11249 -8542
- package/dist/shadow.mjs +408 -15
- package/docs/README.md +14 -6
- package/docs/aggregate-reads.md +22 -0
- package/docs/app-owned-executors.md +8 -0
- package/docs/auto-boundary-and-scoped-explore.md +338 -0
- package/docs/capability-authoring.md +75 -0
- package/docs/conformance.md +16 -0
- package/docs/current-scope.md +60 -28
- package/docs/cursor-plugin.md +20 -3
- package/docs/dsl-reference.md +78 -0
- package/docs/getting-started-own-database.md +39 -35
- package/docs/limitations.md +37 -7
- package/docs/local-mode.md +22 -3
- package/docs/production.md +19 -0
- package/docs/proposal-evidence-freshness.md +334 -0
- package/docs/release-notes.md +63 -4
- package/docs/runner-config-reference.md +46 -0
- package/docs/schema-api-candidates.md +28 -1
- package/docs/security-boundary.md +17 -0
- package/docs/store-lifecycle.md +8 -0
- package/docs/troubleshooting-first-run.md +174 -0
- package/docs/writeback-executors.md +8 -0
- package/examples/app-owned-writeback/command-handler.mjs +0 -0
- package/examples/auto-boundary-churn/README.md +23 -0
- package/examples/auto-boundary-churn/app/page.tsx +8 -0
- package/examples/auto-boundary-churn/docker-compose.yml +16 -0
- package/examples/auto-boundary-churn/package.json +18 -0
- package/examples/auto-boundary-churn/prisma/schema.prisma +36 -0
- package/examples/auto-boundary-churn/seed/postgres.sql +126 -0
- package/examples/mcp-postgres-billing-app-handler/scripts/run-demo.sh +0 -0
- package/examples/reference-support-billing-app/scripts/run-demo.sh +0 -0
- package/examples/support-billing-agent/scripts/run-demo.sh +0 -0
- package/examples/support-billing-agent/scripts/run-evaluation.sh +0 -0
- package/fixtures/compatibility/published-1.5.4/manifest.json +76 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/fixtures/compatibility/published-1.6.0/manifest.json +76 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/fixtures/protocol/MANIFEST.json +37 -7
- package/fixtures/protocol/change-set.freshness-update.v2.json +58 -0
- package/fixtures/protocol/freshness-authority.invoice.v1.json +35 -0
- package/fixtures/protocol/freshness-proof.fresh.v1.json +38 -0
- package/fixtures/protocol/writeback-job.freshness-update.v2.json +50 -0
- package/llms.txt +38 -0
- package/package.json +12 -8
- package/schemas/change-set.v1.schema.json +1 -0
- package/schemas/change-set.v2.schema.json +1 -0
- package/schemas/change-set.v3.schema.json +1 -0
- package/schemas/freshness-authority.v1.schema.json +89 -0
- package/schemas/freshness-proof.v1.schema.json +73 -0
- package/schemas/synapsor.runner.schema.json +50 -1
- package/schemas/writeback-job.v1.schema.json +1 -0
- package/schemas/writeback-job.v2.schema.json +1 -0
- package/schemas/writeback-job.v3.schema.json +1 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# Proposal And Evidence Freshness
|
|
2
|
+
|
|
3
|
+
Runner 1.6.1 adds an optional fail-closed freshness gate for proposals whose
|
|
4
|
+
review depends on live source state.
|
|
5
|
+
|
|
6
|
+
This closes two different review gaps without changing the model-facing MCP
|
|
7
|
+
surface:
|
|
8
|
+
|
|
9
|
+
1. Before a local approval, Runner can re-read the proposal target and refuse
|
|
10
|
+
approval if its exact version changed.
|
|
11
|
+
2. A proposal can declare reviewed supporting rows whose exact versions must
|
|
12
|
+
still match before approval and again at apply.
|
|
13
|
+
|
|
14
|
+
Target-row drift was already blocked by the exact conflict guard at apply.
|
|
15
|
+
Version 1.6.1 does not replace that protection. It adds an earlier review-time
|
|
16
|
+
check and extends the final transaction to declared same-source dependencies.
|
|
17
|
+
|
|
18
|
+
## What Freshness Does And Does Not Mean
|
|
19
|
+
|
|
20
|
+
Keep these controls separate:
|
|
21
|
+
|
|
22
|
+
| Control | What it proves |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| Proposal hash and version | The approval refers to one immutable proposal shape. |
|
|
25
|
+
| Evidence and query fingerprints | The stored review material has not silently changed. |
|
|
26
|
+
| Freshness proof | The target and declared dependencies matched their captured exact versions at one live check. |
|
|
27
|
+
| Approval | A trusted reviewer or policy authorized that exact proposal and proof. |
|
|
28
|
+
| Apply conflict checks | The target and dependencies still match inside the mutation transaction. |
|
|
29
|
+
| Idempotency receipt | Retrying the same completed writeback identity does not duplicate its effect. |
|
|
30
|
+
|
|
31
|
+
A successful approval-time check is not a lock held until apply. Data can
|
|
32
|
+
change one millisecond later, so apply always revalidates again.
|
|
33
|
+
|
|
34
|
+
Runner never refreshes a stale proposal in place. The operator must perform a
|
|
35
|
+
new source read and create a new proposal with a new hash and review.
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
Freshness is a Runner deployment overlay in `synapsor.runner.json`. Version
|
|
40
|
+
1.6.1 adds no DSL clause and no canonical Spec field. Existing hand-authored
|
|
41
|
+
DSL, canonical JSON, contract digests, and `tools/list` output remain unchanged
|
|
42
|
+
when this optional section is absent.
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"proposal_freshness": {
|
|
47
|
+
"billing.propose_credit": {
|
|
48
|
+
"approval": "required",
|
|
49
|
+
"dependencies": [
|
|
50
|
+
{
|
|
51
|
+
"id": "invoice_eligibility",
|
|
52
|
+
"capability": "billing.inspect_invoice",
|
|
53
|
+
"identity_from_arg": "invoice_id",
|
|
54
|
+
"version_column": "updated_at"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The names mean:
|
|
63
|
+
|
|
64
|
+
- `billing.propose_credit`: an existing reviewed proposal capability.
|
|
65
|
+
- `approval: "required"`: every approval decision requires a new short-lived
|
|
66
|
+
live proof.
|
|
67
|
+
- `invoice_eligibility`: an operator-defined stable dependency label.
|
|
68
|
+
- `billing.inspect_invoice`: an existing reviewed single-row read capability.
|
|
69
|
+
- `invoice_id`: an existing bounded scalar argument on the proposal. Its value
|
|
70
|
+
identifies the supporting row through the read capability's fixed lookup.
|
|
71
|
+
- `updated_at`: the exact version/conflict column on that supporting row.
|
|
72
|
+
|
|
73
|
+
The proposal and supporting read must use the same source and trusted context.
|
|
74
|
+
The supporting capability supplies the fixed engine, schema, table, primary
|
|
75
|
+
key, tenant key, optional principal key, and lookup shape. None of those
|
|
76
|
+
identifiers can come from an MCP argument.
|
|
77
|
+
|
|
78
|
+
Strict validation rejects:
|
|
79
|
+
|
|
80
|
+
- unknown or non-proposal policy keys;
|
|
81
|
+
- app-owned or cross-source writeback;
|
|
82
|
+
- unknown, aggregate, protected, or non-single-row dependencies;
|
|
83
|
+
- missing or untrusted tenant scope;
|
|
84
|
+
- incompatible principal scope;
|
|
85
|
+
- missing scalar identity arguments;
|
|
86
|
+
- unsafe or missing version identifiers;
|
|
87
|
+
- duplicate, self-referential, or more than 16 dependencies.
|
|
88
|
+
|
|
89
|
+
Run both static validation and live writeback probes:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
synapsor-runner config validate --config ./synapsor.runner.json
|
|
93
|
+
synapsor-runner doctor --check-writeback --config ./synapsor.runner.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`doctor --check-writeback` performs rollback-only lock probes. The read role
|
|
97
|
+
needs scoped `SELECT`. The writer must be able to lock every declared
|
|
98
|
+
supporting row in the final transaction. PostgreSQL and MySQL may require a
|
|
99
|
+
narrow update/locking privilege in addition to `SELECT`; use a dedicated
|
|
100
|
+
least-privilege writer and verify the exact grants on the deployed database.
|
|
101
|
+
|
|
102
|
+
## Proposal Creation
|
|
103
|
+
|
|
104
|
+
When a freshness-enabled proposal is created, Runner:
|
|
105
|
+
|
|
106
|
+
1. reads the target through the existing reviewed proposal capability;
|
|
107
|
+
2. reads each declared dependency through its reviewed single-row capability
|
|
108
|
+
in a read-only transaction;
|
|
109
|
+
3. captures only the fixed identity, exact version, and bounded
|
|
110
|
+
evidence/query-audit linkage;
|
|
111
|
+
4. sorts dependencies into deterministic lock order;
|
|
112
|
+
5. binds the resulting `synapsor.freshness-authority.v1` object into the
|
|
113
|
+
immutable change set and proposal hash.
|
|
114
|
+
|
|
115
|
+
The authority contains digests and fixed identifiers. It does not add source
|
|
116
|
+
rows, kept-out values, database URLs, credentials, or a second copy of trusted
|
|
117
|
+
tenant/principal values to the proposal.
|
|
118
|
+
|
|
119
|
+
The published protocol representation is inspectable without reading the
|
|
120
|
+
TypeScript implementation:
|
|
121
|
+
|
|
122
|
+
- `schemas/freshness-authority.v1.schema.json` defines the optional authority
|
|
123
|
+
carried by change sets and writeback jobs.
|
|
124
|
+
- `schemas/freshness-proof.v1.schema.json` defines the immutable live-check
|
|
125
|
+
proof stored in the ledger.
|
|
126
|
+
- `fixtures/protocol/change-set.freshness-update.v2.json`,
|
|
127
|
+
`fixtures/protocol/writeback-job.freshness-update.v2.json`,
|
|
128
|
+
`fixtures/protocol/freshness-authority.invoice.v1.json`, and
|
|
129
|
+
`fixtures/protocol/freshness-proof.fresh.v1.json` are hash-manifested
|
|
130
|
+
conformance examples.
|
|
131
|
+
|
|
132
|
+
The JSON Schemas enforce the public structure. The executable protocol
|
|
133
|
+
validator additionally verifies canonical descriptor, dependency-set, and
|
|
134
|
+
proof digests plus cross-field invariants that JSON Schema cannot express.
|
|
135
|
+
|
|
136
|
+
For UPDATE and DELETE, target mode is `exact_guard`. For a bounded set it is
|
|
137
|
+
`frozen_set`. INSERT has no prior target row, so target freshness is
|
|
138
|
+
`not_applicable`; its source uniqueness and idempotency guards still apply.
|
|
139
|
+
|
|
140
|
+
## Approval-Time Check
|
|
141
|
+
|
|
142
|
+
Inspect the newest proposal without copying an ID:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
synapsor-runner proposals check-freshness latest \
|
|
146
|
+
--config ./synapsor.runner.json \
|
|
147
|
+
--store ./.synapsor/local.db
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Add `--details` for per-check digests or `--json` for the versioned
|
|
151
|
+
`synapsor.proposal-freshness-result.v1` document.
|
|
152
|
+
|
|
153
|
+
Stable exit codes are:
|
|
154
|
+
|
|
155
|
+
| Status | Exit code | Meaning |
|
|
156
|
+
| --- | ---: | --- |
|
|
157
|
+
| `fresh` | 0 | Every required target/dependency version matched. |
|
|
158
|
+
| `not_required` | 0 | Legacy proposal; its normal apply guard still applies. |
|
|
159
|
+
| `stale` | 3 | A target or dependency changed, disappeared, or left trusted scope. |
|
|
160
|
+
| `unavailable` | 4 | The source could not be checked; retry may be appropriate. |
|
|
161
|
+
| `invalid` | 5 | Stored or configured authority did not validate. |
|
|
162
|
+
| `unsupported` | 6 | The topology cannot provide the claimed guarantee. |
|
|
163
|
+
|
|
164
|
+
Approval runs the same live check automatically:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
synapsor-runner proposals approve latest \
|
|
168
|
+
--yes \
|
|
169
|
+
--actor billing_reviewer \
|
|
170
|
+
--config ./synapsor.runner.json \
|
|
171
|
+
--store ./.synapsor/local.db
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
A successful check records an immutable `synapsor.freshness-proof.v1` event.
|
|
175
|
+
The proof binds:
|
|
176
|
+
|
|
177
|
+
- proposal ID, hash, and integer version;
|
|
178
|
+
- dependency-set digest;
|
|
179
|
+
- checked and short validity times;
|
|
180
|
+
- source adapter identity;
|
|
181
|
+
- bounded target/supporting counts and result codes;
|
|
182
|
+
- expected/observed version digests, not source values;
|
|
183
|
+
- the proof's own digest.
|
|
184
|
+
|
|
185
|
+
Every human quorum decision receives a distinct live proof. Policy
|
|
186
|
+
auto-approval uses the same evaluator. A stale check records no approval and
|
|
187
|
+
makes the proposal terminal `conflict`. An unavailable check records no
|
|
188
|
+
approval and leaves it `pending_review`.
|
|
189
|
+
|
|
190
|
+
## Apply-Time Revalidation
|
|
191
|
+
|
|
192
|
+
Apply remains an operator/worker action outside MCP:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
synapsor-runner apply latest \
|
|
196
|
+
--yes \
|
|
197
|
+
--config ./synapsor.runner.json \
|
|
198
|
+
--store ./.synapsor/local.db
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
For direct SQL PostgreSQL/MySQL writeback, Runner:
|
|
202
|
+
|
|
203
|
+
1. begins the existing source transaction;
|
|
204
|
+
2. locks supporting rows in deterministic source/schema/table/identity order;
|
|
205
|
+
3. rechecks each exact version under trusted tenant and principal scope;
|
|
206
|
+
4. locks and rechecks the target row or every frozen set member;
|
|
207
|
+
5. performs the existing guarded mutation only if all checks pass;
|
|
208
|
+
6. finalizes the configured source or Runner-ledger receipt behavior.
|
|
209
|
+
|
|
210
|
+
PostgreSQL uses parameterized `SELECT ... FOR UPDATE` and quoted reviewed
|
|
211
|
+
identifiers. MySQL uses the equivalent InnoDB locking read. A stale supporting
|
|
212
|
+
row returns `FRESHNESS_DEPENDENCY_STALE`, zero affected rows, and rolls back the
|
|
213
|
+
whole transaction. A stale target continues to use the exact target conflict
|
|
214
|
+
path. A stale conflict is never converted to `already_applied`.
|
|
215
|
+
|
|
216
|
+
For a bounded set, one stale member or one stale dependency aborts every member.
|
|
217
|
+
|
|
218
|
+
## Timeline
|
|
219
|
+
|
|
220
|
+
Change before approval:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
proposal captures target v4 + invoice v8
|
|
224
|
+
invoice moves to v9
|
|
225
|
+
reviewer approves
|
|
226
|
+
-> live preflight sees v9 != v8
|
|
227
|
+
-> no approval, no source mutation
|
|
228
|
+
-> create a new read and proposal
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Change after approval:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
proposal captures target v4 + invoice v8
|
|
235
|
+
approval preflight succeeds and binds proof
|
|
236
|
+
invoice moves to v9
|
|
237
|
+
trusted apply starts
|
|
238
|
+
-> transaction locks invoice and sees v9 != v8
|
|
239
|
+
-> conflict, zero source mutation
|
|
240
|
+
-> create a new read and proposal
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The second timeline is why approval-time freshness can never replace
|
|
244
|
+
apply-time concurrency control.
|
|
245
|
+
|
|
246
|
+
## Supporting Evidence Example
|
|
247
|
+
|
|
248
|
+
Assume `credits.propose_account_credit` changes an account row, but eligibility
|
|
249
|
+
depends on a separate invoice:
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
target account version 12 (unchanged)
|
|
253
|
+
supporting invoice status=open, version 7
|
|
254
|
+
proposal credit $25 because invoice is open
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
If a payment process closes the invoice and advances it to version 8 while the
|
|
258
|
+
account stays at version 12, the target guard alone would still pass. Declaring
|
|
259
|
+
the invoice read as a freshness dependency makes approval or apply fail closed
|
|
260
|
+
on the invoice version mismatch.
|
|
261
|
+
|
|
262
|
+
Freshness checks the reviewed exact version, not whether the current value
|
|
263
|
+
"looks equivalent." Returning a row to its old value does not revive a proposal
|
|
264
|
+
that already became stale.
|
|
265
|
+
|
|
266
|
+
## Ledger, Replay, Reports, And Metrics
|
|
267
|
+
|
|
268
|
+
Use the no-ID lifecycle view:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
synapsor-runner lifecycle --details --store ./.synapsor/local.db
|
|
272
|
+
synapsor-runner replay show latest --details --store ./.synapsor/local.db
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Lifecycle and replay retain the proof chain: authority, proof event, approval
|
|
276
|
+
proof digest, apply result, receipt, and replay linkage. Backup/restore and the
|
|
277
|
+
shared PostgreSQL runtime store preserve the same versioned records.
|
|
278
|
+
|
|
279
|
+
Compliance reports include only bounded freshness metadata and digests. Metrics
|
|
280
|
+
separate checks, stale target/supporting outcomes, blocked approvals, and
|
|
281
|
+
apply-time blocks. Logs never include source rows or credential values.
|
|
282
|
+
|
|
283
|
+
## Cloud And App-Owned Executors
|
|
284
|
+
|
|
285
|
+
Cloud-linked approval remains proposal/digest authority. Cloud may retain
|
|
286
|
+
bounded freshness metadata, but it does not connect to or read the customer
|
|
287
|
+
database. A Runner next to the source revalidates dependencies when it applies
|
|
288
|
+
a Cloud-approved lease. Cloud outage never enables weaker local approval or
|
|
289
|
+
apply authority.
|
|
290
|
+
|
|
291
|
+
Strict freshness currently supports same-database direct SQL writeback only.
|
|
292
|
+
Runner rejects strict freshness configuration for app-owned handlers and
|
|
293
|
+
cross-source dependencies because it cannot place those checks and effects in
|
|
294
|
+
one transaction.
|
|
295
|
+
|
|
296
|
+
An app-owned executor can implement equivalent preconditions, but the
|
|
297
|
+
application must own and test:
|
|
298
|
+
|
|
299
|
+
- source reads and locking;
|
|
300
|
+
- tenant/principal authorization;
|
|
301
|
+
- exact expected versions;
|
|
302
|
+
- transaction boundaries;
|
|
303
|
+
- idempotency and ambiguous outcomes;
|
|
304
|
+
- safe receipts.
|
|
305
|
+
|
|
306
|
+
Do not describe those application guarantees as Runner's atomic direct-SQL
|
|
307
|
+
freshness guarantee.
|
|
308
|
+
|
|
309
|
+
## Security Boundary
|
|
310
|
+
|
|
311
|
+
Freshness adds no model-facing approval, apply, activation, bypass, SQL, table,
|
|
312
|
+
column, scope, or policy argument. Existing `tools/list` output is unchanged.
|
|
313
|
+
|
|
314
|
+
It also does not replace:
|
|
315
|
+
|
|
316
|
+
- correct monotonic version columns;
|
|
317
|
+
- least-privilege read/write roles;
|
|
318
|
+
- PostgreSQL RLS, restricted views, or tenant-bound credentials;
|
|
319
|
+
- application authorization;
|
|
320
|
+
- source backups and recovery testing;
|
|
321
|
+
- operator identity and host/store protection.
|
|
322
|
+
|
|
323
|
+
The dedicated live gate is:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
corepack pnpm test:proposal-freshness
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
It runs disposable PostgreSQL and MySQL scenarios for approval preflight,
|
|
330
|
+
proof-bound human/quorum/policy approval, target/supporting drift before and
|
|
331
|
+
after approval, source and Runner-ledger receipts, bounded-set rollback,
|
|
332
|
+
reversible UPDATE, DELETE, shared runtime state, Cloud-approved local
|
|
333
|
+
revalidation, writer lock probes, idempotent retry, and kept-out-value
|
|
334
|
+
non-disclosure.
|
package/docs/release-notes.md
CHANGED
|
@@ -10,7 +10,66 @@ 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.
|
|
13
|
+
## 1.6.1 (prepared, not published)
|
|
14
|
+
|
|
15
|
+
### Fail-closed proposal and evidence freshness
|
|
16
|
+
|
|
17
|
+
- An optional `proposal_freshness` Runner overlay can require a live target and
|
|
18
|
+
explicitly declared same-source supporting-row check immediately before
|
|
19
|
+
every local approval.
|
|
20
|
+
- Each successful human, quorum, or policy approval references a distinct
|
|
21
|
+
short-lived proof bound to the exact proposal hash/version and dependency
|
|
22
|
+
set. Stale and unavailable checks record no approval.
|
|
23
|
+
- Direct PostgreSQL/MySQL apply locks and rechecks dependencies inside the
|
|
24
|
+
mutation transaction. Source drift after approval returns a conflict and
|
|
25
|
+
changes zero rows; bounded sets roll back completely.
|
|
26
|
+
- `proposals check-freshness latest`, Workbench gating, lifecycle, replay,
|
|
27
|
+
compliance reports, metrics, logs, and `doctor --check-writeback` expose the
|
|
28
|
+
bounded proof and operational state without source rows, kept-out values,
|
|
29
|
+
trusted scope values, or credentials.
|
|
30
|
+
- Cloud does not read the source. A local Runner revalidates a Cloud-approved
|
|
31
|
+
job before apply. Strict app-owned and cross-source freshness remains an
|
|
32
|
+
explicitly unsupported topology.
|
|
33
|
+
- Existing contracts, exact digests, DSL, model-facing tool lists, and
|
|
34
|
+
non-freshness deployments keep their prior behavior.
|
|
35
|
+
|
|
36
|
+
Prepared package version: `@synapsor/runner@1.6.1`.
|
|
37
|
+
`@synapsor/spec@1.5.0` and `@synapsor/dsl@1.5.0` are unchanged. Nothing has
|
|
38
|
+
been published by this repository change.
|
|
39
|
+
|
|
40
|
+
## 1.6.0 (published 2026-07-23)
|
|
41
|
+
|
|
42
|
+
### Connect, Explore, Protect
|
|
43
|
+
|
|
44
|
+
- A fresh interactive `start --from-env DATABASE_URL` can inspect the whole
|
|
45
|
+
staging schema and structured Prisma/Drizzle/OpenAPI/Synapsor artifacts,
|
|
46
|
+
then emit a disabled candidate boundary without executing adopter code,
|
|
47
|
+
reading source rows, or using an LLM.
|
|
48
|
+
- The local Workbench requires explicit review of scope, fields, aggregate
|
|
49
|
+
measures/dimensions/time buckets, one-hop relationships, privacy budgets,
|
|
50
|
+
role/grant/RLS posture, profile, generation lock, and exact digest.
|
|
51
|
+
- The temporary Cursor authoring entry exposes only `app.describe_data` and
|
|
52
|
+
`app.explore_data`. Typed row and PM-style aggregate plans are bounded by the
|
|
53
|
+
activated authority, run read-only, and cannot introduce SQL, identifiers,
|
|
54
|
+
tenant/principal identity, or wider limits.
|
|
55
|
+
- Aggregate Explore supports reviewed count/distinct/sum/avg, categorical and
|
|
56
|
+
time grouping, bounded comparisons/top-N, cohort suppression, and durable
|
|
57
|
+
anti-differencing/extraction/rate limits. It is descriptive analysis, not a
|
|
58
|
+
causation claim.
|
|
59
|
+
- Protect This Query writes public DSL, canonical JSON, tests, and a disabled
|
|
60
|
+
named capability. Exact-digest activation disables broad Explore; production
|
|
61
|
+
serves only the named protected tool.
|
|
62
|
+
- Scoped Explore is absent from production, unknown-profile, shared HTTP,
|
|
63
|
+
remote, and non-loopback `tools/list`. Write-capable, owner, superuser,
|
|
64
|
+
`BYPASSRLS`, or unverifiable credentials cannot enable source-row Explore.
|
|
65
|
+
- Existing 1.x projects do not need Workbench, generation locks, rescans, or
|
|
66
|
+
new fields. Published legacy contracts preserve exact normalization/digests,
|
|
67
|
+
and established CLI/headless/CI routes keep their behavior.
|
|
68
|
+
|
|
69
|
+
Published package versions: `@synapsor/runner@1.6.0`,
|
|
70
|
+
`@synapsor/dsl@1.5.0`, and `@synapsor/spec@1.5.0`.
|
|
71
|
+
|
|
72
|
+
## 1.5.4 (published 2026-07-22)
|
|
14
73
|
|
|
15
74
|
### Networked MCP authentication hardening
|
|
16
75
|
|
|
@@ -47,9 +106,9 @@ for the Synapsor Cloud CLI.
|
|
|
47
106
|
environment variable. Explicit ENVIRONMENT, verified HTTP_CLAIM, verified
|
|
48
107
|
CLOUD_SESSION, and STATIC_DEV behavior remains distinct.
|
|
49
108
|
|
|
50
|
-
|
|
51
|
-
`@synapsor/dsl@1.4.4`. `@synapsor/spec@1.4.2` and the Cloud CLI
|
|
52
|
-
unchanged.
|
|
109
|
+
Published package versions: `@synapsor/runner@1.5.4` and
|
|
110
|
+
`@synapsor/dsl@1.4.4`. `@synapsor/spec@1.4.2` and the Cloud CLI were
|
|
111
|
+
unchanged.
|
|
53
112
|
|
|
54
113
|
## 1.5.3 (published 2026-07-21)
|
|
55
114
|
|
|
@@ -453,6 +453,52 @@ Distinct verified subjects fill quorum slots; one subject cannot count twice.
|
|
|
453
453
|
A rejection is terminal. Policy auto-approval is deferred when quorum is
|
|
454
454
|
greater than one.
|
|
455
455
|
|
|
456
|
+
## Proposal freshness
|
|
457
|
+
|
|
458
|
+
`proposal_freshness` is an optional Runner-only deployment overlay. It does not
|
|
459
|
+
change the public DSL or canonical contract and does not alter legacy proposal
|
|
460
|
+
or `tools/list` behavior when absent.
|
|
461
|
+
|
|
462
|
+
```json
|
|
463
|
+
{
|
|
464
|
+
"proposal_freshness": {
|
|
465
|
+
"billing.propose_credit": {
|
|
466
|
+
"approval": "required",
|
|
467
|
+
"dependencies": [
|
|
468
|
+
{
|
|
469
|
+
"id": "invoice_eligibility",
|
|
470
|
+
"capability": "billing.inspect_invoice",
|
|
471
|
+
"identity_from_arg": "invoice_id",
|
|
472
|
+
"version_column": "updated_at"
|
|
473
|
+
}
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The top-level key is an existing proposal capability. `approval` must be
|
|
481
|
+
`required`. Every dependency must reference an existing reviewed single-row
|
|
482
|
+
read on the same source/context and map one bounded scalar proposal argument to
|
|
483
|
+
that read's fixed lookup. The read capability supplies schema, table, primary
|
|
484
|
+
key, tenant/principal keys, and source; the model cannot supply or widen them.
|
|
485
|
+
At most 16 dependencies are allowed.
|
|
486
|
+
|
|
487
|
+
The proposal target and dependencies are read again before every approval.
|
|
488
|
+
Direct SQL apply locks and rechecks them again inside the source transaction.
|
|
489
|
+
Strict freshness is rejected for app-owned and cross-source effects because
|
|
490
|
+
Runner cannot make those checks atomic with the external effect.
|
|
491
|
+
|
|
492
|
+
Use:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
synapsor-runner proposals check-freshness latest --config ./synapsor.runner.json
|
|
496
|
+
synapsor-runner doctor --check-writeback --config ./synapsor.runner.json
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
The complete validation, privilege, lifecycle, and error-code contract is in
|
|
500
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
501
|
+
|
|
456
502
|
## Rate limits
|
|
457
503
|
|
|
458
504
|
```json
|
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Reviewed Candidates From Prisma, Drizzle, And OpenAPI
|
|
2
2
|
|
|
3
|
+
Runner 1.6.0 uses these same bounded static parsers as evidence in the
|
|
4
|
+
whole-application [Auto Boundary](auto-boundary-and-scoped-explore.md) flow.
|
|
5
|
+
The database catalog remains authoritative for database structure; Prisma,
|
|
6
|
+
Drizzle, OpenAPI, and existing Synapsor definitions contribute deterministic
|
|
7
|
+
names, relationships, and structured review evidence. None of them
|
|
8
|
+
independently grant authority.
|
|
9
|
+
|
|
10
|
+
For a fresh interactive staging project, prefer:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
synapsor-runner start --from-env DATABASE_URL
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That combines all detected structured sources into one disabled candidate
|
|
17
|
+
graph, generation lock, and Workbench review. It never executes adopter code,
|
|
18
|
+
samples source rows before activation, uses an LLM, or overwrites an active
|
|
19
|
+
contract.
|
|
20
|
+
|
|
21
|
+
The individual commands below remain useful for CI, focused review, and
|
|
22
|
+
backward-compatible workflows.
|
|
23
|
+
|
|
3
24
|
Use these generators after schema or API inspection when you want a review
|
|
4
25
|
starting point without granting authority:
|
|
5
26
|
|
|
@@ -42,11 +63,17 @@ They do not decide which tenant or principal is authoritative, which fields are
|
|
|
42
63
|
safe to expose, which writes are valid, business bounds, approval policy, or
|
|
43
64
|
auto-approval. A field-name heuristic is not data classification.
|
|
44
65
|
|
|
45
|
-
|
|
66
|
+
In the individual-generator path, review `generation-review.json` and
|
|
67
|
+
`REVIEW.md`, replace every
|
|
46
68
|
`review_required_*` placeholder, run the generated tests and a
|
|
47
69
|
[Shadow study](shadow-studies.md), then deliberately copy reviewed definitions
|
|
48
70
|
into an active contract through code review.
|
|
49
71
|
|
|
72
|
+
In Auto Boundary, Workbench presents the unresolved scope, field, aggregate,
|
|
73
|
+
relationship, privacy, and role-posture decisions together. Exact-digest
|
|
74
|
+
activation enables only the reviewed local authoring boundary. Generated named
|
|
75
|
+
capabilities still begin disabled and require their own activation.
|
|
76
|
+
|
|
50
77
|
## Input Safety
|
|
51
78
|
|
|
52
79
|
Input is bounded to 2 MiB, 50 objects, 128 fields per object, and 200 generated
|
|
@@ -120,6 +120,16 @@ explicit host-level administrative boundary.
|
|
|
120
120
|
Proposal tools read the current row through the read credential, store evidence
|
|
121
121
|
and an exact before/after diff, and leave the source database unchanged.
|
|
122
122
|
|
|
123
|
+
For an explicitly freshness-enabled proposal, Runner also captures exact
|
|
124
|
+
version authority for the target and reviewed same-source supporting rows.
|
|
125
|
+
Before each local approval it performs a read-only live check and binds the
|
|
126
|
+
successful proof to that approval. This improves review integrity but does not
|
|
127
|
+
hold a lock through apply. The trusted direct SQL apply path therefore locks
|
|
128
|
+
and rechecks the dependencies again inside the mutation transaction. A stale
|
|
129
|
+
or unverifiable dependency produces no mutation and is never silently
|
|
130
|
+
refreshed. See
|
|
131
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
132
|
+
|
|
123
133
|
Code-first Safe Actions do not create authority when a file is edited. Runner
|
|
124
134
|
parses the restricted TypeScript object without importing or executing it,
|
|
125
135
|
compiles it into a digest-addressed disabled canonical draft, and keeps the
|
|
@@ -153,11 +163,18 @@ outside the model-facing MCP server and verifies:
|
|
|
153
163
|
- conflict/version guard;
|
|
154
164
|
- idempotency key;
|
|
155
165
|
- operation-specific version or source-unique deduplication guard;
|
|
166
|
+
- declared same-source supporting-version guards, when freshness is required;
|
|
156
167
|
- job expiry;
|
|
157
168
|
- exactly one reviewed row or every member of one bounded frozen set.
|
|
158
169
|
|
|
159
170
|
If any authority check cannot be verified, the write fails closed.
|
|
160
171
|
|
|
172
|
+
Strict freshness is intentionally limited to same-database direct SQL
|
|
173
|
+
writeback. Runner rejects app-owned or cross-source strict freshness because it
|
|
174
|
+
cannot claim one atomic transaction around those effects. Cloud can govern an
|
|
175
|
+
approval, but it does not read the source; the local Runner revalidates source
|
|
176
|
+
state before a Cloud-approved job can mutate data.
|
|
177
|
+
|
|
161
178
|
For direct SQL writeback, the writer connection is the env var named by the
|
|
162
179
|
source `write_url_env` in `synapsor.runner.json`. With `source_db` receipt
|
|
163
180
|
authority, the source mutation and receipt commit atomically; the receipt table
|
package/docs/store-lifecycle.md
CHANGED
|
@@ -48,6 +48,7 @@ then proposal id as the tie-breaker. The default view answers:
|
|
|
48
48
|
- what capability and business object the model requested;
|
|
49
49
|
- which trusted tenant and principal scoped it;
|
|
50
50
|
- approval state and progress;
|
|
51
|
+
- required/live freshness state and the proof digest bound to each approval;
|
|
51
52
|
- whether a writeback job or intent exists;
|
|
52
53
|
- the latest guarded outcome and whether the source changed;
|
|
53
54
|
- replay and Cloud-link status; and
|
|
@@ -123,6 +124,7 @@ The existing commands remain useful when you need one record type:
|
|
|
123
124
|
| Question | Focused command |
|
|
124
125
|
| --- | --- |
|
|
125
126
|
| What did the model propose? | `synapsor-runner proposals show latest --details` |
|
|
127
|
+
| Is the latest proposal still fresh enough to review? | `synapsor-runner proposals check-freshness latest --config ./synapsor.runner.json` |
|
|
126
128
|
| What data supported it? | `synapsor-runner evidence list --proposal <proposal-id>` then `evidence show <evidence-id> --details` |
|
|
127
129
|
| What query was run? | `synapsor-runner query-audit list --proposal <proposal-id>` |
|
|
128
130
|
| Did guarded writeback apply? | `synapsor-runner receipts list --proposal <proposal-id>` |
|
|
@@ -135,6 +137,12 @@ The existing commands remain useful when you need one record type:
|
|
|
135
137
|
it materializes a job and is therefore an operator mutation, not a read-only
|
|
136
138
|
view.
|
|
137
139
|
|
|
140
|
+
`proposals check-freshness` is source-read-only but is not a ledger-pure
|
|
141
|
+
inspection: it contacts the configured source and records an immutable proof
|
|
142
|
+
event. The `lifecycle` command never does that; it only reports the most recent
|
|
143
|
+
stored proof and approval linkage. See
|
|
144
|
+
[Proposal And Evidence Freshness](proposal-evidence-freshness.md).
|
|
145
|
+
|
|
138
146
|
## Server leases
|
|
139
147
|
|
|
140
148
|
MCP server modes write a small lease file next to the store:
|