@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.
Files changed (81) hide show
  1. package/CHANGELOG.md +68 -2
  2. package/README.md +131 -124
  3. package/dist/authoring.mjs +405 -9
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/local-ui.d.ts +6 -1
  6. package/dist/local-ui.d.ts.map +1 -1
  7. package/dist/runner.mjs +17206 -12169
  8. package/dist/runtime.mjs +11249 -8542
  9. package/dist/shadow.mjs +408 -15
  10. package/docs/README.md +14 -6
  11. package/docs/aggregate-reads.md +22 -0
  12. package/docs/app-owned-executors.md +8 -0
  13. package/docs/auto-boundary-and-scoped-explore.md +338 -0
  14. package/docs/capability-authoring.md +75 -0
  15. package/docs/conformance.md +16 -0
  16. package/docs/current-scope.md +60 -28
  17. package/docs/cursor-plugin.md +20 -3
  18. package/docs/dsl-reference.md +78 -0
  19. package/docs/getting-started-own-database.md +39 -35
  20. package/docs/limitations.md +37 -7
  21. package/docs/local-mode.md +22 -3
  22. package/docs/production.md +19 -0
  23. package/docs/proposal-evidence-freshness.md +334 -0
  24. package/docs/release-notes.md +63 -4
  25. package/docs/runner-config-reference.md +46 -0
  26. package/docs/schema-api-candidates.md +28 -1
  27. package/docs/security-boundary.md +17 -0
  28. package/docs/store-lifecycle.md +8 -0
  29. package/docs/troubleshooting-first-run.md +174 -0
  30. package/docs/writeback-executors.md +8 -0
  31. package/examples/app-owned-writeback/command-handler.mjs +0 -0
  32. package/examples/auto-boundary-churn/README.md +23 -0
  33. package/examples/auto-boundary-churn/app/page.tsx +8 -0
  34. package/examples/auto-boundary-churn/docker-compose.yml +16 -0
  35. package/examples/auto-boundary-churn/package.json +18 -0
  36. package/examples/auto-boundary-churn/prisma/schema.prisma +36 -0
  37. package/examples/auto-boundary-churn/seed/postgres.sql +126 -0
  38. package/examples/mcp-postgres-billing-app-handler/scripts/run-demo.sh +0 -0
  39. package/examples/reference-support-billing-app/scripts/run-demo.sh +0 -0
  40. package/examples/support-billing-agent/scripts/run-demo.sh +0 -0
  41. package/examples/support-billing-agent/scripts/run-evaluation.sh +0 -0
  42. package/fixtures/compatibility/published-1.5.4/manifest.json +76 -0
  43. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
  44. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
  45. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
  46. package/fixtures/compatibility/published-1.5.4/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
  47. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
  48. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
  49. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
  50. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
  51. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
  52. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
  53. package/fixtures/compatibility/published-1.5.4/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
  54. package/fixtures/compatibility/published-1.6.0/manifest.json +76 -0
  55. package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
  56. package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
  57. package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
  58. package/fixtures/compatibility/published-1.6.0/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
  59. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
  60. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
  61. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
  62. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
  63. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
  64. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
  65. package/fixtures/compatibility/published-1.6.0/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
  66. package/fixtures/protocol/MANIFEST.json +37 -7
  67. package/fixtures/protocol/change-set.freshness-update.v2.json +58 -0
  68. package/fixtures/protocol/freshness-authority.invoice.v1.json +35 -0
  69. package/fixtures/protocol/freshness-proof.fresh.v1.json +38 -0
  70. package/fixtures/protocol/writeback-job.freshness-update.v2.json +50 -0
  71. package/llms.txt +38 -0
  72. package/package.json +12 -8
  73. package/schemas/change-set.v1.schema.json +1 -0
  74. package/schemas/change-set.v2.schema.json +1 -0
  75. package/schemas/change-set.v3.schema.json +1 -0
  76. package/schemas/freshness-authority.v1.schema.json +89 -0
  77. package/schemas/freshness-proof.v1.schema.json +73 -0
  78. package/schemas/synapsor.runner.schema.json +50 -1
  79. package/schemas/writeback-job.v1.schema.json +1 -0
  80. package/schemas/writeback-job.v2.schema.json +1 -0
  81. 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.
@@ -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.5.4 (prepared, not published)
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
- Prepared package versions: `@synapsor/runner@1.5.4` and
51
- `@synapsor/dsl@1.4.4`. `@synapsor/spec@1.4.2` and the Cloud CLI are
52
- unchanged. Nothing has been published by this repository change.
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
- Review `generation-review.json` and `REVIEW.md`, replace every
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
@@ -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: