@synapsor/runner 1.4.1 → 1.4.121

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/docs/README.md CHANGED
@@ -70,6 +70,12 @@ no-database demo, wire your database, then read deeper concepts.
70
70
  - [Recipes](recipes.md): starter business-capability templates.
71
71
  - [JSON Schema](../schemas/synapsor.runner.schema.json): editor validation for
72
72
  `synapsor.runner.json`.
73
+ - [Contract Review](contract-review.md): LSP setup, plain-language explanation,
74
+ and deterministic lint/SARIF output.
75
+ - [Contract Testing](contract-testing.md): adopter-owned static and disposable
76
+ PostgreSQL/MySQL allow/deny/redaction assertions.
77
+ - [Bounded Aggregate Reads](aggregate-reads.md): fixed scalar count/sum/avg,
78
+ tenant scope, suppression, and no-row evidence.
73
79
 
74
80
  ## 06 Serve MCP
75
81
 
@@ -113,6 +119,10 @@ no-database demo, wire your database, then read deeper concepts.
113
119
  and lifecycle inspection.
114
120
  - `examples/mysql-refund-agent/`: MySQL order/refund review example using the
115
121
  same proposal, approval, guarded writeback, and replay loop.
122
+ - [Scoped Ledger Reports](compliance-reports.md): object/principal JSON,
123
+ Markdown, and PDF exports with digest/signature verification.
124
+ - [Graduated Trust](graduated-trust.md): off-by-default operator
125
+ recommendations that never auto-activate a policy.
116
126
 
117
127
  ## 09 App-Owned Handlers
118
128
 
@@ -0,0 +1,49 @@
1
+ # Bounded Aggregate Reads
2
+
3
+ An `aggregate_read` capability returns one reviewed scalar rather than source
4
+ rows. It is intended for questions such as a tenant-scoped overdue balance
5
+ total where exposing individual records would be unnecessary.
6
+
7
+ ```sql
8
+ CREATE CAPABILITY billing.overdue_balance_total
9
+ DESCRIPTION 'Return the reviewed overdue balance total for the trusted tenant.'
10
+ USING CONTEXT local_operator
11
+ SOURCE billing_postgres
12
+ ON public.invoices
13
+ PRIMARY KEY id
14
+ TENANT KEY tenant_id
15
+ AGGREGATE READ SUM balance_cents
16
+ SELECT WHERE status = 'overdue'
17
+ MIN GROUP SIZE 5
18
+ REQUIRE EVIDENCE
19
+ END
20
+ ```
21
+
22
+ Compile the packaged example with:
23
+
24
+ ```bash
25
+ synapsor-runner dsl compile ./fixtures/dsl/aggregate-read.synapsor.sql \
26
+ --out ./synapsor.contract.json --strict
27
+ ```
28
+
29
+ A permitted call returns one aggregate scalar; an undersized group returns a
30
+ stable suppressed result. Neither result contains source rows or member IDs.
31
+
32
+ Supported operations are `COUNT ROWS`, `COUNT NON NULL column`, `SUM column`,
33
+ and `AVG column`. The source, table/view, tenant key, function, column, optional
34
+ equality selection, and minimum group size are contract-authored. The first
35
+ release permits no model arguments, dynamic columns, joins, grouping, arbitrary
36
+ expressions, or model-controlled predicates.
37
+
38
+ When fewer records match than `MIN GROUP SIZE`, the stable result is suppressed
39
+ and contains no aggregate value or member identity. Allowed results contain one
40
+ scalar plus evidence/query-audit handles. Evidence records the contract digest,
41
+ trusted scope reference, reviewed operation, fixed predicate summary, and
42
+ suppression state; it never stores member rows or IDs.
43
+
44
+ PostgreSQL and MySQL execution is parameterized and uses the configured
45
+ statement timeout. A dependency outage or statement timeout returns a safe,
46
+ retryable unavailable result without exposing a driver error. Minimum-group
47
+ suppression reduces single-record inference; it does not solve every statistical
48
+ inference risk. Review the underlying view, database role, and aggregation
49
+ policy as well.
@@ -129,20 +129,25 @@ CREATE CAPABILITY tickets.close_overdue
129
129
  CONFLICT GUARD version
130
130
  LOOKUP reason BY id
131
131
  ARG reason STRING REQUIRED MAX LENGTH 100
132
- ALLOW READ id, tenant_id, status, cost_cents, version
132
+ ALLOW READ id, tenant_id, risk_level, case_status, cost_cents, version
133
133
  REQUIRE EVIDENCE
134
134
  PROPOSE ACTION close_overdue UPDATE SET
135
- SELECT WHERE status = 'overdue'
135
+ SELECT WHERE risk_level = 'high' AND case_status = 'active'
136
136
  MAX ROWS 10
137
137
  MAX TOTAL cost_cents BEFORE 50000
138
- ALLOW WRITE status
139
- PATCH status = 'closed'
138
+ ALLOW WRITE case_status
139
+ PATCH case_status = 'closed'
140
140
  ADVANCE VERSION version USING INTEGER INCREMENT
141
141
  APPROVAL ROLE ops_manager
142
142
  WRITEBACK DIRECT SQL
143
143
  END
144
144
  ```
145
145
 
146
+ Each `SELECT WHERE` term is a reviewer-fixed literal equality, and every term
147
+ must match. Up to eight terms may be joined by `AND`; quoted `AND` text remains
148
+ part of the value. `OR`, parentheses, inequalities, ranges, and free-form or
149
+ model-authored predicates are not supported.
150
+
146
151
  Compile the contract and create `synapsor.runner.json`:
147
152
 
148
153
  ```bash
@@ -0,0 +1,42 @@
1
+ # Export Scoped Ledger Reports
2
+
3
+ Runner can export a deterministic chronology for one business object or one
4
+ principal inside an explicit tenant scope:
5
+
6
+ ```bash
7
+ synapsor-runner report --object invoice:INV-3001 --tenant tenant_acme \
8
+ --store ./.synapsor/local.db --format markdown --out ./invoice-report.md
9
+
10
+ synapsor-runner report --principal support.operator --tenant tenant_acme \
11
+ --store ./.synapsor/local.db --format pdf --out ./operator-report.pdf
12
+ ```
13
+
14
+ Runner prints the output path and canonical `sha256:...` integrity digest. A
15
+ successful verification prints `PASS`, `REPORT_DIGEST_VERIFIED`, or
16
+ `REPORT_SIGNATURE_VERIFIED` when a public key is supplied.
17
+
18
+ For `storage.shared_postgres.mode = "runtime_store"`, include `--config
19
+ ./synapsor.runner.json`; Runner reads through a bounded local bridge to the same
20
+ shared ledger.
21
+
22
+ Reports include scoped proposal, query-audit, approval/rejection, writeback,
23
+ receipt, replay, compensation, and graduated-trust decision metadata when those
24
+ records exist. Evidence rows are never exported. Kept-out values, credentials,
25
+ keys, raw driver errors, and database URLs are excluded.
26
+
27
+ JSON, Markdown, and PDF reports carry a canonical manifest digest. Optional
28
+ operator signing binds the export to the existing key model:
29
+
30
+ ```bash
31
+ synapsor-runner report --object invoice:INV-3001 --tenant tenant_acme \
32
+ --store ./.synapsor/local.db --format json --out ./invoice-report.json \
33
+ --signing-key ./operator-private.pem --key-id review-key-1
34
+
35
+ synapsor-runner report verify ./invoice-report.json \
36
+ --public-key ./operator-public.pem
37
+ ```
38
+
39
+ Verification detects content, ordering, digest, and signature tampering. A
40
+ verified export is tamper-evident; it does not make local SQLite immutable,
41
+ append-only compliance storage. Protect report files and signing keys with the
42
+ same care as the ledger.
@@ -28,6 +28,7 @@ Current fixture groups:
28
28
  - `manual-approval`
29
29
  - `auto-approval`
30
30
  - `aggregate-policy-limits`
31
+ - `aggregate-read`
31
32
  - `numeric-bounds`
32
33
  - `bounded-set-threats`
33
34
  - `reversible-change-sets`
@@ -42,6 +43,12 @@ selection, count/value caps, frozen-version drift checks, atomic rollback,
42
43
  exact receipts, hard-delete side-effect refusal, and human approval. Adapter
43
44
  tests and `corepack pnpm test:bounded-set` complete the live PostgreSQL/MySQL
44
45
  matrix.
46
+ The aggregate-read fixture proves a reviewer-fixed scalar operation, trusted
47
+ tenant scope, fixed equality selection, minimum-group suppression, and an
48
+ evidence/query-audit surface containing no member rows or identities. The live
49
+ `corepack pnpm test:aggregate-read` gate runs COUNT/SUM/AVG, suppression,
50
+ timeout, and dependency classification against disposable PostgreSQL and
51
+ MySQL.
45
52
  The reversible-change-set fixture proves that undo is a new reviewed
46
53
  compensation proposal, not rollback: apply-time receipts capture only
47
54
  allowlisted inverse data, compensation uses fresh guards and exact members,
@@ -72,6 +79,8 @@ Run:
72
79
 
73
80
  ```bash
74
81
  corepack pnpm --filter @synapsor-runner/mcp-server test
82
+ corepack pnpm test:contract-conformance
83
+ corepack pnpm test:aggregate-read
75
84
  ```
76
85
 
77
86
  The spec package also validates every conformance contract:
@@ -0,0 +1,57 @@
1
+ # Review Contracts Before Serving Them
2
+
3
+ Runner uses the same DSL parser and canonical Spec validator for compilation,
4
+ editor diagnostics, explanation, and lint. These tools reduce authoring errors;
5
+ they do not replace a human review of database permissions, visible fields,
6
+ tenant binding, or business policy.
7
+
8
+ ## Explain The Boundary
9
+
10
+ ```bash
11
+ synapsor-runner contract explain ./contract.synapsor.sql --format markdown
12
+ synapsor-runner contract explain ./synapsor.contract.json --format json
13
+ ```
14
+
15
+ The explanation lists trusted context bindings, model-facing arguments, fixed
16
+ targets and selections, visible and kept-out fields, evidence requirements,
17
+ proposal/writeback controls, approval, bounds, reversibility, and unresolved
18
+ runtime dependencies. It is derived from normalized canonical contract JSON.
19
+ It never reads environment values or prints database URLs, tokens, keys, or
20
+ evidence rows.
21
+
22
+ ## Lint In CI
23
+
24
+ ```bash
25
+ synapsor-runner contract lint ./contract.synapsor.sql --strict
26
+ synapsor-runner contract lint ./synapsor.contract.json \
27
+ --config ./synapsor.runner.json --format sarif --out ./contract-lint.sarif
28
+ ```
29
+
30
+ `--strict` is equivalent to `--fail-on warning`; the default fails on errors.
31
+ Lint rule IDs, ordering, severity, and source ranges are deterministic. Rules
32
+ cover objective review gaps such as missing descriptions/evidence, unbounded
33
+ strings, unresolved wiring, irreversible operations, and policy/writeback
34
+ contradictions. Lint does not claim to discover every sensitive column.
35
+
36
+ Expected successful output ends with:
37
+
38
+ ```text
39
+ Summary: 0 error / 0 warning / N info
40
+ ```
41
+
42
+ ## Language Server
43
+
44
+ ```bash
45
+ synapsor-runner language-server --stdio
46
+ ```
47
+
48
+ The stdio LSP supports `.synapsor.sql` and legacy `.synapsor` documents. It
49
+ publishes parser/validator diagnostics and provides context-aware completion,
50
+ hover, and formatting. Configure a generic LSP client to launch the command
51
+ above with the workspace as its working directory. For VS Code, use any stdio
52
+ language-client extension that can associate both filename patterns with that
53
+ command. Generic SQL highlighting remains useful for `.synapsor.sql`; the LSP
54
+ adds Synapsor-specific semantics.
55
+
56
+ The server never suggests raw SQL, model-authored predicates, approval tools,
57
+ or clauses that are illegal for the current capability kind.
@@ -0,0 +1,47 @@
1
+ # Test A Contract Boundary
2
+
3
+ Adopter-owned contract tests exercise reviewed allow/deny behavior without an
4
+ LLM. The public manifest schema is
5
+ [`schemas/synapsor.contract-tests.schema.json`](../schemas/synapsor.contract-tests.schema.json).
6
+
7
+ ```bash
8
+ synapsor-runner contract test \
9
+ --contract ./synapsor.contract.json \
10
+ --tests ./synapsor.contract-tests.json \
11
+ --config ./synapsor.runner.json
12
+ ```
13
+
14
+ Static mode checks tool exposure, operator-only boundaries, argument limits,
15
+ transition guards, bounded-set caps, and other assertions that do not require a
16
+ database. Add `--live` to call the actual MCP runtime for scoped reads,
17
+ proposals, evidence/replay redaction, and source-unchanged checks.
18
+
19
+ ```bash
20
+ synapsor-runner contract test \
21
+ --contract ./synapsor.contract.json \
22
+ --tests ./synapsor.contract-tests.json \
23
+ --config ./synapsor.runner.json \
24
+ --live --format junit --out ./contract-tests.xml
25
+ ```
26
+
27
+ Live mode accepts local/disposable PostgreSQL and MySQL targets. Runner refuses
28
+ remote hosts by default; `--allow-remote` is an explicit operator override and
29
+ does not grant implicit write permission. Use synthetic fixtures and a
30
+ disposable database. Unknown assertions and unresolved required tests fail
31
+ rather than being skipped.
32
+
33
+ A successful run ends with a stable count such as:
34
+
35
+ ```text
36
+ Summary: 6 passed / 0 failed / 6 total
37
+ ```
38
+
39
+ Supported assertions cover valid scoped tools, cross-tenant denial, kept-out
40
+ fields, argument constraints, transition guards, set caps, unchanged source
41
+ state before approval, and the absence of model-facing approval/writeback.
42
+ Trusted tenant and principal values belong in test setup, not tool arguments.
43
+
44
+ The flagship example includes a working manifest at
45
+ [`examples/support-plan-credit/synapsor.contract-tests.json`](../examples/support-plan-credit/synapsor.contract-tests.json).
46
+ Contract tests prove the declared cases, not every possible threat or database
47
+ permission error.
@@ -71,6 +71,7 @@ END
71
71
  ARG invoice_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Invoice id.'
72
72
  ARG amount_cents NUMBER REQUIRED MIN 1 MAX 2500 DESCRIPTION 'Amount in cents.'
73
73
  ARG confirmed BOOLEAN REQUIRED
74
+ ARG risk_level STRING ENUM('low', 'medium', 'high') REQUIRED
74
75
  ```
75
76
 
76
77
  Argument types are `STRING`/`TEXT`, `NUMBER`, and `BOOLEAN`/`BOOL`.
@@ -80,12 +81,41 @@ Argument types are `STRING`/`TEXT`, `NUMBER`, and `BOOLEAN`/`BOOL`.
80
81
  - `MIN n` and `MAX n` are numeric bounds for `NUMBER`.
81
82
  - `MAX LENGTH n` bounds `STRING`/`TEXT`. Legacy text `MAX n` remains accepted.
82
83
  - `LOOKUP arg BY column` binds one argument to the target row lookup.
84
+ - `ENUM(value, ...)` restricts an argument to reviewed string, numeric, or
85
+ boolean values of the declared type. Enums contain 1 through 64 unique,
86
+ non-null values and preserve declared order.
83
87
 
84
88
  In spec 0.1, lookup is primary-key-only. The `BY` column must equal the declared
85
89
  `PRIMARY KEY`. A different column fails with `LOOKUP_COLUMN_UNSUPPORTED`; Runner
86
90
  never silently rewrites it. List/filter queries require a reviewed view or a
87
91
  different capability design.
88
92
 
93
+ ## Aggregate read
94
+
95
+ An aggregate capability returns one scalar and no source rows:
96
+
97
+ ```sql
98
+ CREATE CAPABILITY billing.overdue_balance_total
99
+ DESCRIPTION 'Return overdue balance for the trusted tenant.'
100
+ USING CONTEXT local_operator
101
+ SOURCE billing_postgres
102
+ ON public.invoices
103
+ PRIMARY KEY id
104
+ TENANT KEY tenant_id
105
+ AGGREGATE READ SUM balance_cents
106
+ SELECT WHERE status = 'overdue'
107
+ MIN GROUP SIZE 5
108
+ REQUIRE EVIDENCE
109
+ END
110
+ ```
111
+
112
+ Use `COUNT ROWS`, `COUNT NON NULL column`, `SUM column`, or `AVG column`.
113
+ `SELECT WHERE` is the same contract-fixed equality AST used by reviewed set
114
+ operations. `MIN GROUP SIZE` is mandatory and must be 2 through 1,000,000.
115
+ Aggregate reads cannot declare model arguments, lookup, visible row fields,
116
+ proposal clauses, joins, grouping, or arbitrary expressions. See [Bounded
117
+ Aggregate Reads](aggregate-reads.md).
118
+
89
119
  ## Read surface and evidence
90
120
 
91
121
  ```sql
@@ -162,7 +192,7 @@ bounds, exact version guards, and human/operator approval:
162
192
 
163
193
  ```sql
164
194
  PROPOSE ACTION close_overdue UPDATE SET
165
- SELECT WHERE status = 'overdue'
195
+ SELECT WHERE risk_level = 'high' AND case_status = 'active'
166
196
  MAX ROWS 10
167
197
  MAX TOTAL balance_cents BEFORE 50000
168
198
  ALLOW WRITE status
@@ -172,11 +202,14 @@ bounds, exact version guards, and human/operator approval:
172
202
  WRITEBACK DIRECT SQL
173
203
  ```
174
204
 
175
- `SELECT WHERE` accepts one or more literal equality terms joined by `AND`.
176
- Columns, operators, values, ordering, ranges, and raw SQL cannot come from a
177
- model argument. Runner reads `MAX ROWS + 1` and rejects overflow rather than
178
- truncating. `MAX TOTAL column BEFORE|AFTER|ABSOLUTE DELTA maximum` is a
179
- reviewer-visible aggregate value bound.
205
+ `SELECT WHERE` accepts one through eight literal equality terms joined by
206
+ `AND`. The separator is recognized only outside quoted literals, so
207
+ `description = 'salt AND pepper'` remains one term. `OR`, parentheses,
208
+ inequalities, ranges, trailing expressions, and free-form or model-authored
209
+ predicates are rejected during compilation. Runner reads `MAX ROWS + 1` and
210
+ rejects overflow rather than truncating. `MAX TOTAL column
211
+ BEFORE|AFTER|ABSOLUTE DELTA maximum` is a reviewer-visible aggregate value
212
+ bound.
180
213
 
181
214
  Batch INSERT takes a complete typed item array:
182
215
 
@@ -368,7 +368,14 @@ npx -y -p @synapsor/runner synapsor-runner smoke call --config ./synapsor.runner
368
368
 
369
369
  `smoke call` uses the same runtime as the MCP server. It records evidence and
370
370
  query audit for read tools, or creates a proposal for proposal tools, then
371
- prints the commands to inspect evidence/proposals/replay from the local store.
371
+ prints the commands to inspect evidence/proposals/replay. With the default
372
+ storage topology those records are in local SQLite. With
373
+ `storage.shared_postgres.mode = "runtime_store"`, Runner `1.4.12` and later
374
+ write them to the authoritative shared Postgres ledger and include `--config`
375
+ in follow-up commands. The supplied `--store` path is compatibility plumbing
376
+ for those CLI commands; it does not receive an orphan proposal copy. If the
377
+ shared ledger is unavailable, `smoke call` fails safely and does not fall back
378
+ to SQLite.
372
379
 
373
380
  The snippets contain the local command and args. They must not contain database
374
381
  URLs, passwords, approval tools, commit tools, or write credentials.
@@ -0,0 +1,64 @@
1
+ # Graduated Trust Recommendations
2
+
3
+ Graduated trust is an opt-in operator workflow that evaluates scoped ledger
4
+ history and recommends a bounded policy threshold change. It is disabled by
5
+ default. It never auto-approves itself, changes the active contract, pushes a
6
+ contract, or activates a registry version.
7
+
8
+ ```json
9
+ {
10
+ "graduated_trust": {
11
+ "enabled": true,
12
+ "kill_switch": false,
13
+ "criteria": [{
14
+ "capability": "support.propose_plan_credit",
15
+ "policy": "small_credit",
16
+ "field": "plan_credit_cents",
17
+ "minimum_human_reviews": 20,
18
+ "window_days": 30,
19
+ "maximum_rejection_rate": 0.05,
20
+ "maximum_conflict_rate": 0.01,
21
+ "maximum_failure_rate": 0.01,
22
+ "maximum_revert_rate": 0.01,
23
+ "maximum_threshold_increase": 500,
24
+ "absolute_ceiling": 5000
25
+ }]
26
+ }
27
+ }
28
+ ```
29
+
30
+ Evaluate human-reviewed outcomes for one trusted tenant/capability/policy:
31
+
32
+ ```bash
33
+ synapsor-runner policy recommend --contract ./synapsor.contract.json \
34
+ --config ./synapsor.runner.json --tenant tenant_acme \
35
+ --capability support.propose_plan_credit --policy small_credit \
36
+ --store ./.synapsor/local.db
37
+ ```
38
+
39
+ Eligible history produces `RECOMMENDATION_CREATED` and a pending `ptr_...`
40
+ identifier. Disabled, insufficient, stale, or out-of-policy history returns a
41
+ stable non-success code and creates no recommendation.
42
+
43
+ Auto-approved outcomes do not count as independent human evidence. Missing or
44
+ legacy provenance, mismatched contract digest/version, tampered approvals,
45
+ cross-scope records, insufficient samples, or excessive rejection, conflict,
46
+ failure, or revert rates fail closed. `kill_switch: true` disables evaluation
47
+ even when `enabled` remains true.
48
+
49
+ A recommendation remains operator-only. List it with `policy recommendations
50
+ list`. Approval or rejection requires a cryptographically verified `signed_key`
51
+ or `jwt_oidc` operator identity. Rejection is terminal. Approval permits only
52
+ an explicit export of a separate reviewable contract artifact:
53
+
54
+ ```bash
55
+ synapsor-runner policy recommendations export ptr_... --tenant tenant_acme \
56
+ --contract ./synapsor.contract.json \
57
+ --out ./synapsor.contract.recommended.json --actor policy-reviewer --yes \
58
+ --store ./.synapsor/local.db
59
+ ```
60
+
61
+ Export rechecks the base contract digest, version, and current threshold. The
62
+ artifact is not activated. Activation remains an explicit operator or Cloud
63
+ registry action. Recommendation, decision, and export metadata remain in the
64
+ local or shared Postgres runtime ledger and can appear in scoped reports.
@@ -49,6 +49,12 @@ enterprise SLA.
49
49
  - Static MCP database risk review.
50
50
  - Local indexed search for proposals, evidence bundles, query audit, writeback
51
51
  receipts, and proposal replay.
52
+ - DSL enum arguments and fixed, tenant-scoped aggregate count/sum/avg tools
53
+ with mandatory minimum-group suppression and no source-row output.
54
+ - Contract LSP, explanation, deterministic lint, adopter-owned contract tests,
55
+ and scoped tamper-evident JSON/Markdown/PDF ledger reports.
56
+ - Off-by-default graduated-trust recommendations that require verified operator
57
+ review and explicit artifact export without activation.
52
58
 
53
59
  ## Runtime Contract
54
60
 
@@ -81,6 +87,10 @@ truth for the model-facing tools.
81
87
  - Prompt-injection prevention.
82
88
  - Unbounded/high-throughput or multi-region ledger scale.
83
89
  - Managed fleet, SLA, compliance certification, or production support guarantee.
90
+ - Arbitrary aggregate expressions, joins, grouping, dynamic columns,
91
+ model-controlled aggregate predicates, or a statistical privacy guarantee.
92
+ - Automatic policy widening or activation from graduated-trust metrics.
93
+ - Immutable/WORM compliance storage from the local report exporter.
84
94
 
85
95
  ## Important External Database Semantics
86
96
 
@@ -340,6 +340,16 @@ from `url_env`, auto-runs the shared-ledger migration, and serializes runtime
340
340
  mutations with a transaction-scoped advisory lock. The MCP tools still expose no
341
341
  database URLs or write credentials to the model.
342
342
 
343
+ `smoke call` uses the same runtime-store resolver as MCP serving. Its evidence,
344
+ query audit, proposal, events, and replay records therefore land directly in
345
+ the shared Postgres ledger and are immediately visible to another Runner using
346
+ the same config. `--store` remains accepted so the printed follow-up CLI
347
+ commands have a compatibility/bridge path, but that SQLite path is not an
348
+ authoritative copy and normally is not created by the smoke call. Shared-ledger
349
+ connection failure returns the safe availability error and a nonzero exit; it
350
+ never causes a local fallback. This consistency fix is present in Runner
351
+ `1.4.12` and later.
352
+
343
353
  `runtime_store` covers MCP serving, CLI approval/apply, and supervised worker
344
354
  runs. For CLI mutations, Runner restores the shared ledger into a temporary
345
355
  local store while holding the Postgres advisory lock, runs the existing local
@@ -10,6 +10,59 @@ 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.4.121 (prepared, not published)
14
+
15
+ ### Contract trust surface and bounded-set parser correctness
16
+
17
+ - Fixes BUG-018, where a documented fixed predicate containing multiple
18
+ equality terms joined by `AND` could compile as one string-valued term and
19
+ then fail closed with no matching source rows.
20
+ - The DSL compiler now consumes the complete clause, keeps `AND` inside quoted
21
+ strings, preserves ordered typed literals, and rejects malformed or
22
+ unsupported expressions before serving or proposal creation.
23
+ - This does not add free-form SQL predicates: only fixed literal equality terms
24
+ joined by `AND` are supported. `OR`, parentheses, inequalities, ranges, and
25
+ model-authored predicates remain unsupported.
26
+ - PostgreSQL and MySQL live verification proves all terms are applied together
27
+ within trusted tenant scope, source rows remain unchanged before approval,
28
+ and guarded apply, receipt/replay, retry, caps, and drift checks remain green.
29
+ - Contract authors gain one parser-backed review path: stdio LSP diagnostics,
30
+ completion, hover, and formatting; plain-language explanation; deterministic
31
+ lint; and adopter-owned static/disposable contract tests.
32
+ - Scoped object/principal reports export redacted JSON, Markdown, or PDF ledger
33
+ metadata with digest/signature verification. They are tamper-evident exports,
34
+ not a claim that local SQLite is immutable compliance storage.
35
+ - DSL enum arguments compile to the canonical enum shape and are enforced by
36
+ every Runner transport. Canonical aggregate reads return one fixed
37
+ tenant-scoped COUNT/SUM/AVG scalar, suppress small groups, and persist no
38
+ member rows or identities in evidence/query audit.
39
+ - Graduated trust remains disabled by default and operator-only. It can create
40
+ and export a verified, bounded policy recommendation artifact, but cannot
41
+ auto-approve, push, or activate it.
42
+ - C++/Cloud validators and exporters preserve the new additive enum/aggregate
43
+ fields for canonical round-trip compatibility.
44
+
45
+ Prepared package versions: `@synapsor/spec@1.4.1`,
46
+ `@synapsor/dsl@1.4.2`, and `@synapsor/runner@1.4.121`.
47
+
48
+ ## 1.4.12 (prepared, not published)
49
+
50
+ ### Runtime-store smoke-call consistency
51
+
52
+ - Fixes BUG-017, where `smoke call` could put proposal artifacts in the
53
+ requested local SQLite path even though the config selected authoritative
54
+ shared Postgres `runtime_store` mode.
55
+ - Smoke calls now use the same runtime storage resolver as MCP tool calls. A
56
+ second Runner can immediately inspect the proposal, evidence, query audit,
57
+ events, and replay from the shared ledger.
58
+ - Shared-ledger unavailability fails closed with a safe retryable error,
59
+ nonzero exit status, no credential leakage, and no local orphan proposal.
60
+ - Local SQLite and mirror modes retain their existing behavior; no source row
61
+ changes before the normal external approval/apply path.
62
+
63
+ Prepared package version: `@synapsor/runner@1.4.12`.
64
+ `@synapsor/dsl` remains `1.4.1`; `@synapsor/spec` remains `1.4.0`.
65
+
13
66
  ## 1.4.1 (prepared, not published)
14
67
 
15
68
  ### Bounded-set digest compatibility patch
@@ -38,6 +38,7 @@ Unknown keys fail when `strict` is true (the default).
38
38
  | `session_auth` | HTTP claims | HS256 development or asymmetric RS256/ES256 session-token verification. |
39
39
  | `rate_limits` | No | Operational fixed-window limits; fleet-wide only with shared `runtime_store`. |
40
40
  | `metrics` | No | Separately authorized scrapeable HTTP metrics. Disabled by default. |
41
+ | `graduated_trust` | No | Off-by-default, operator-only policy recommendation criteria and kill switch. |
41
42
  | `executors` | No | App-owned writeback wiring. |
42
43
  | `cloud` | Cloud mode | Scoped Cloud adapter configuration. |
43
44
 
@@ -375,6 +376,21 @@ metrics token; the MCP bearer does not authorize metrics. Labels are bounded to
375
376
  trusted tenant, capability, source, engine, and readiness component. Object
376
377
  IDs, principals, URLs, tokens, and raw errors are never labels.
377
378
 
379
+ ## Graduated trust
380
+
381
+ `graduated_trust` is runtime/operator policy, not model-facing authority. It is
382
+ disabled unless `enabled` is exactly `true`; `kill_switch: true` stops all
383
+ evaluation. Each criterion fixes one capability, approval policy, numeric
384
+ field, minimum human-reviewed sample (10..10000), window (1..365 days), maximum
385
+ rejection/conflict/failure/revert rates, maximum threshold increment, and
386
+ absolute ceiling. Optional `workspace_id` and `project_id` further scope stored
387
+ recommendations.
388
+
389
+ Auto-approved outcomes never count as human evidence. Recommendation decisions
390
+ require verified operator identity. Approval only permits exporting a new
391
+ contract artifact bound to the current digest/version; Runner never activates
392
+ it. See [Graduated Trust Recommendations](graduated-trust.md).
393
+
378
394
  ## Operator identity
379
395
 
380
396
  Local development compatibility uses an explicitly unverified environment
@@ -40,6 +40,12 @@ The model does not receive:
40
40
  - commit/writeback tools;
41
41
  - trusted tenant or principal authority as ordinary model arguments.
42
42
 
43
+ Reviewed aggregate tools expose one scalar only. Their function, column,
44
+ tenant key, optional equality selection, and minimum-group threshold are fixed
45
+ in the contract; the model receives no predicate arguments or member rows.
46
+ Suppression reduces single-record inference but does not replace statistical
47
+ privacy review. See [Bounded Aggregate Reads](aggregate-reads.md).
48
+
43
49
  Trusted context comes from local configuration, environment bindings, or Cloud
44
50
  session context in Cloud mode. Tenant, principal, and authorization scope must
45
51
  not be accepted from the model as authority.
@@ -121,6 +127,13 @@ approve/reject actions. It does not expose raw SQL, database URLs, write
121
127
  credentials, approval tools, commit tools, or controls that widen reviewed
122
128
  tables/columns.
123
129
 
130
+ Contract lint and tests are review aids rather than a proof of complete
131
+ security. Scoped report exports omit evidence rows and kept-out values and are
132
+ tamper-evident when their digest/signature verifies; local SQLite is not an
133
+ immutable compliance service. Graduated-trust evaluation is operator-only,
134
+ disabled by default, and can recommend/export a separate artifact but cannot
135
+ approve itself or activate policy.
136
+
124
137
  Synapsor Runner supports reviewed single-row CRUD and the narrowly bounded set
125
138
  path documented above. It does not support arbitrary SQL, DDL, UPSERT,
126
139
  model-generated predicates, unbounded sets, or cross-table direct writeback.
@@ -12,6 +12,26 @@ Use JSON for automation:
12
12
  npx -y -p @synapsor/runner synapsor-runner doctor --first-run --json
13
13
  ```
14
14
 
15
+ ## Smoke Proposal Missing From Another Runner
16
+
17
+ What happened:
18
+
19
+ `smoke call` returned a proposal id, but `proposals list --config ...` on a
20
+ second Runner cannot find it.
21
+
22
+ Fix:
23
+
24
+ 1. Verify `synapsor-runner --version` is `1.4.12` or later.
25
+ 2. Confirm both commands use a config whose
26
+ `storage.shared_postgres.mode` is `runtime_store` and whose `url_env` and
27
+ `schema` identify the same ledger.
28
+ 3. Run `store shared-postgres status --url-env <ENV> --schema <SCHEMA>`.
29
+
30
+ In `runtime_store` mode, `--store` is not the authoritative ledger. Runner does
31
+ not fall back to that SQLite path when shared Postgres is unavailable. Versions
32
+ before `1.4.12` could orphan smoke-call artifacts locally; recreate that test
33
+ proposal after upgrading.
34
+
15
35
  ## Docker Missing
16
36
 
17
37
  What happened:
@@ -64,6 +64,7 @@ INSERT INTO public.invoices (id, tenant_id, status, late_fee_cents, waiver_reaso
64
64
  ('INV-ACME', 'acme', 'overdue', 2500, NULL, '2026-07-12T12:00:00Z'),
65
65
  ('INV-GLOBEX', 'globex', 'overdue', 3100, NULL, '2026-07-12T12:00:00Z'),
66
66
  ('INV-RATECO', 'rateco', 'overdue', 900, NULL, '2026-07-12T12:00:00Z'),
67
+ ('INV-SMOKE-CALL', 'acme', 'overdue', 2100, NULL, '2026-07-12T12:00:00Z'),
67
68
  ('INV-BATCH-A', 'acme', 'overdue', 1100, NULL, '2026-07-12T12:00:00Z'),
68
69
  ('INV-BATCH-B', 'acme', 'overdue', 1300, NULL, '2026-07-12T12:00:00Z'),
69
70
  ('INV-QUORUM-RACE', 'acme', 'overdue', 1400, NULL, '2026-07-12T12:00:00Z'),