@synapsor/runner 0.1.14 → 0.1.16

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
@@ -41,6 +41,10 @@ no-database demo, wire your database, then read deeper concepts.
41
41
  - [Capability Authoring](capability-authoring.md): define read/proposal
42
42
  capabilities, model-facing descriptions, result envelopes, trusted context,
43
43
  and writeback guards.
44
+ - [DSL Reference](dsl-reference.md): complete supported grammar, clause order,
45
+ compiled meaning, and constraints.
46
+ - [Runner Config Reference](runner-config-reference.md): every public wiring
47
+ key, default, environment binding, and path-resolution rule.
44
48
  - [Recipes](recipes.md): starter business-capability templates.
45
49
  - [JSON Schema](../schemas/synapsor.runner.schema.json): editor validation for
46
50
  `synapsor.runner.json`.
@@ -5,9 +5,18 @@ source of truth for trusted context, resources, capabilities, evidence,
5
5
  proposal shape, and writeback intent.
6
6
 
7
7
  ```text
8
- contract.synapsor -> synapsor.contract.json -> synapsor.runner.json
8
+ contract.synapsor.sql -> synapsor.contract.json -> synapsor.runner.json
9
9
  ```
10
10
 
11
+ Use `.synapsor.sql` as the preferred DSL source extension because editors can
12
+ provide generic SQL highlighting. Legacy `.synapsor` files remain supported;
13
+ the suffix does not change DSL semantics or generated canonical JSON.
14
+
15
+ For exact clause grammar, ordering, constraints, fixed-string patches, and the
16
+ primary-key-only lookup rule, see the [DSL Reference](dsl-reference.md). For all
17
+ local wiring keys and path rules, see the
18
+ [Runner Config Reference](runner-config-reference.md).
19
+
11
20
  Use `synapsor.runner.json` for local wiring: database env var names, SQLite
12
21
  store path, MCP transport settings, and local development flags. The model sees
13
22
  semantic capabilities such as `billing.inspect_invoice`, not raw SQL, table
@@ -69,7 +78,7 @@ END
69
78
  Compile and validate:
70
79
 
71
80
  ```bash
72
- synapsor-runner dsl compile ./contract.synapsor --out ./synapsor.contract.json --strict
81
+ synapsor-runner dsl compile ./contract.synapsor.sql --out ./synapsor.contract.json --strict
73
82
  synapsor-runner contract validate ./synapsor.contract.json
74
83
  synapsor-runner contract bundle ./synapsor.contract.json --out ./synapsor-runner-bundle
75
84
  synapsor-runner cloud push ./synapsor.contract.json --dry-run
@@ -2,6 +2,11 @@
2
2
 
3
3
  Conformance fixtures prove behavior, not just JSON shape.
4
4
 
5
+ The conformance artifacts are canonical JSON. When authoring a source contract
6
+ for these checks, prefer `.synapsor.sql` for generic editor SQL highlighting;
7
+ `.synapsor` remains backward compatible and the filename does not affect the
8
+ compiled contract semantics.
9
+
5
10
  `@synapsor/spec` owns the fixtures under:
6
11
 
7
12
  ```text
@@ -33,6 +38,9 @@ fixture directories:
33
38
  - `docs/dsl-json-parity.md`, DSL/spec tests, and the
34
39
  `numeric-bounds-transition` C++ export fixture cover richer DSL/JSON parity
35
40
  fields such as `returns_hint`, numeric bounds, and transition guards.
41
+ - `packages/dsl/fixtures/invalid/non-primary-lookup.synapsor.sql` proves the
42
+ DSL rejects a lookup meaning that canonical spec 0.1 cannot represent,
43
+ instead of silently rewriting it to primary-key access.
36
44
  - The main Synapsor repo script `scripts/verify_contract_cloud_push.sh`
37
45
  verifies real Cloud push, retrieval, idempotent versioning, unauthorized
38
46
  rejection, and runner-bundle download against a live local control-plane.
package/docs/doctor.md CHANGED
@@ -63,9 +63,9 @@ The target-table probe uses fixed schema/table/column identifiers from the
63
63
  reviewed config. It does not accept model SQL, user SQL, arbitrary table names,
64
64
  or arbitrary column names. It runs inside a transaction and rolls back.
65
65
 
66
- The receipt-table probe can create `synapsor_writeback_receipts` if the writer
67
- has permission. If your policy does not allow Runner to create tables in the
68
- application schema, pre-create the table and grant access:
66
+ An administrator must pre-create `synapsor_writeback_receipts` and grant the
67
+ steady-state writer access. The doctor probe does not execute DDL or require
68
+ schema `CREATE`:
69
69
 
70
70
  ```bash
71
71
  synapsor-runner writeback migration --engine postgres --schema synapsor
@@ -0,0 +1,197 @@
1
+ # Synapsor DSL Reference
2
+
3
+ The Synapsor DSL is a reviewable SQL-like authoring format that compiles to the
4
+ canonical `@synapsor/spec` contract. Prefer `.synapsor.sql`; legacy `.synapsor`
5
+ files remain valid. The filename does not change semantics.
6
+
7
+ Validate and compile with strict safety warnings enabled:
8
+
9
+ ```bash
10
+ synapsor-runner dsl validate ./contract.synapsor.sql --strict
11
+ synapsor-runner dsl compile ./contract.synapsor.sql \
12
+ --out ./synapsor.contract.json --strict
13
+ ```
14
+
15
+ Keywords are case-insensitive. Blocks start with `CREATE ...` and end with
16
+ `END` or `END;`. Lines may end in semicolons. `--` starts a line comment.
17
+ Unsupported clauses fail explicitly.
18
+
19
+ ## Agent context
20
+
21
+ ```sql
22
+ CREATE AGENT CONTEXT local_operator
23
+ BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
24
+ BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
25
+ TENANT BINDING tenant_id
26
+ PRINCIPAL BINDING principal
27
+ END
28
+ ```
29
+
30
+ | Clause | Meaning |
31
+ | --- | --- |
32
+ | `BIND name FROM source key [REQUIRED]` | Defines trusted context. Sources: `SESSION`, `ENV`/`ENVIRONMENT`, `CLOUD_SESSION`, `STATIC_DEV`, `HTTP_CLAIM`. Model tool arguments cannot set these bindings. |
33
+ | `TENANT BINDING name` | Selects the binding used for tenant scope. Defaults to a binding named `tenant_id`. |
34
+ | `PRINCIPAL BINDING name` | Selects the actor binding. Defaults to a binding named `principal`. |
35
+
36
+ At least one `BIND` is required. The selected tenant/principal bindings must be
37
+ provided by the trusted runtime environment, not by the model.
38
+
39
+ ## Capability identity and target
40
+
41
+ ```sql
42
+ CREATE CAPABILITY billing.inspect_invoice
43
+ DESCRIPTION 'Inspect one invoice in the trusted tenant.'
44
+ RETURNS HINT 'Returns reviewed fields and an evidence handle.'
45
+ USING CONTEXT local_operator
46
+ SOURCE billing_postgres
47
+ ON public.invoices
48
+ PRIMARY KEY id
49
+ TENANT KEY tenant_id
50
+ CONFLICT GUARD updated_at
51
+ ...
52
+ END
53
+ ```
54
+
55
+ | Clause | Requirement and compiled meaning |
56
+ | --- | --- |
57
+ | `CREATE [AGENT] CAPABILITY namespace.name` | Starts a qualified capability. |
58
+ | `DESCRIPTION 'text'` | Model-facing `tools/list` description. Recommended for every tool and required by strict review for proposal quality. |
59
+ | `RETURNS HINT 'text'` | Model-facing result guidance. |
60
+ | `USING CONTEXT name` | Required. References an agent context. |
61
+ | `SOURCE name` | Source key that must match `synapsor.runner.json.sources`. |
62
+ | `ON schema.table` | Required fixed target. Table/schema are never model inputs. |
63
+ | `PRIMARY KEY column` | Fixed single-row target key. Defaults to `id` in DSL 0.1. Declare it explicitly. |
64
+ | `TENANT KEY column` | Required in DSL 0.1. Adds trusted tenant scope to every read/write. |
65
+ | `CONFLICT GUARD column` | Captures the row-version value for exact guarded writeback. Prefer a monotonic version or native-precision timestamp. |
66
+
67
+ ## Arguments and lookup
68
+
69
+ ```sql
70
+ LOOKUP invoice_id BY id
71
+ ARG invoice_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Invoice id.'
72
+ ARG amount_cents NUMBER REQUIRED MIN 1 MAX 2500 DESCRIPTION 'Amount in cents.'
73
+ ARG confirmed BOOLEAN REQUIRED
74
+ ```
75
+
76
+ Argument types are `STRING`/`TEXT`, `NUMBER`, and `BOOLEAN`/`BOOL`.
77
+
78
+ - `REQUIRED` makes the model-facing argument mandatory.
79
+ - `DESCRIPTION 'text'` documents the argument in MCP `tools/list`.
80
+ - `MIN n` and `MAX n` are numeric bounds for `NUMBER`.
81
+ - `MAX LENGTH n` bounds `STRING`/`TEXT`. Legacy text `MAX n` remains accepted.
82
+ - `LOOKUP arg BY column` binds one argument to the target row lookup.
83
+
84
+ In spec 0.1, lookup is primary-key-only. The `BY` column must equal the declared
85
+ `PRIMARY KEY`. A different column fails with `LOOKUP_COLUMN_UNSUPPORTED`; Runner
86
+ never silently rewrites it. List/filter queries require a reviewed view or a
87
+ different capability design.
88
+
89
+ ## Read surface and evidence
90
+
91
+ ```sql
92
+ ALLOW READ id, tenant_id, status, amount_cents, updated_at
93
+ KEEP OUT card_token, private_notes
94
+ REQUIRE EVIDENCE
95
+ MAX ROWS 1
96
+ ```
97
+
98
+ `ALLOW READ` is required and becomes the visible-field allowlist. `KEEP OUT`
99
+ records fields that must remain outside the model/evidence surface. Keep-out
100
+ fields must not also be visible. `REQUIRE EVIDENCE` records the scoped read and
101
+ query audit. `MAX ROWS n` bounds the result; local 0.1 capabilities are designed
102
+ around one primary-key row.
103
+
104
+ ## Proposal and patch
105
+
106
+ Read capabilities end after the read clauses. A proposal capability adds:
107
+
108
+ ```sql
109
+ PROPOSE ACTION waive_late_fee
110
+ ALLOW WRITE late_fee_cents, waiver_reason
111
+ PATCH late_fee_cents = 0
112
+ PATCH waiver_reason = ARG reason
113
+ PATCH status = 'approved'
114
+ PATCH reviewed = TRUE
115
+ PATCH obsolete_note = NULL
116
+ ```
117
+
118
+ `PROPOSE ACTION` must precede proposal-only clauses. `ALLOW WRITE` is the exact
119
+ patch-column allowlist. Each `PATCH` uses one of:
120
+
121
+ - `ARG name`: value comes from a validated model argument;
122
+ - a quoted fixed string;
123
+ - a fixed number;
124
+ - `TRUE`, `FALSE`, or `NULL`.
125
+
126
+ Fixed strings such as `PATCH status = 'approved'` are supported. The patch is
127
+ saved as a proposal; it is not executed by the model-facing tool.
128
+
129
+ ## Bounds and transitions
130
+
131
+ ```sql
132
+ BOUND amount_cents 1..2500
133
+ BOUND discount_cents ..500
134
+ BOUND score 1..
135
+ TRANSITION status ALLOW reported -> approved|rejected
136
+ TRANSITION status FROM current_status ALLOW open -> closed, held -> open
137
+ ```
138
+
139
+ `BOUND column min..max` applies to a patched numeric column. Either side may be
140
+ open, but not both. Strict mode warns when a numeric argument reaches a patch
141
+ without argument bounds or a patch bound.
142
+
143
+ `TRANSITION patched_column [FROM source_column] ALLOW from -> to|to, ...`
144
+ allowlists state changes. Without `FROM`, the current value is read from the
145
+ patched column. Values may be identifiers or quoted strings.
146
+
147
+ ## Approval and writeback
148
+
149
+ ```sql
150
+ APPROVAL ROLE billing_lead
151
+ AUTO APPROVE WHEN amount_cents <= 2500
152
+ WRITEBACK DIRECT SQL
153
+ ```
154
+
155
+ `APPROVAL ROLE role` records the required local reviewer role. Local OSS
156
+ approval identity is operator-provided; enterprise identity/RBAC belongs to the
157
+ Cloud boundary.
158
+
159
+ `AUTO APPROVE WHEN field <= non_negative_integer` is supported only for a
160
+ numeric patched field and must follow `APPROVAL ROLE`. Its maximum cannot exceed
161
+ the field's `BOUND`. Policy approval still does not apply the write.
162
+
163
+ Writeback forms:
164
+
165
+ | Clause | Meaning |
166
+ | --- | --- |
167
+ | `WRITEBACK DIRECT SQL` | Runner performs one guarded single-row update after approval. |
168
+ | `WRITEBACK APP HANDLER EXECUTOR name` | Runner calls a configured app-owned executor after approval. URL/token wiring stays outside the contract. |
169
+ | `WRITEBACK CLOUD WORKER` | Delegates approved execution to Cloud worker infrastructure. |
170
+ | `WRITEBACK NONE` | Proposal-only; local apply is intentionally unavailable. |
171
+
172
+ ## Workflow declarations
173
+
174
+ ```sql
175
+ CREATE AGENT WORKFLOW support.refund_review
176
+ USING CONTEXT local_operator
177
+ ALLOW CAPABILITY support.inspect_order
178
+ ALLOW CAPABILITY support.propose_refund
179
+ REQUIRE EVIDENCE
180
+ APPROVAL REQUIRED ROLE support_lead
181
+ CHECKPOINT PROPOSAL ONLY
182
+ END
183
+ ```
184
+
185
+ `USING CONTEXT` and at least one `ALLOW CAPABILITY` are required. Optional
186
+ clauses are `REQUIRE EVIDENCE`, `APPROVAL REQUIRED ROLE role`, and `CHECKPOINT
187
+ NONE|EVERY STEP|PROPOSAL ONLY`. Contracts can declare workflows; Runner 0.1 does
188
+ not execute arbitrary Cloud workflow DAGs, settlement, branching, or auto-merge.
189
+
190
+ ## Unsupported syntax
191
+
192
+ Unknown clauses fail instead of being ignored. Cloud-generated concepts such as
193
+ `ROOT EXTERNAL`, `JOIN EXTERNAL`, `RETURN ANSWER WITH CITATIONS`, `AUTO BRANCH`,
194
+ and `AUTO MERGE` are not local DSL 0.1 clauses.
195
+
196
+ The canonical JSON output, not parser implementation details, is the portable
197
+ contract. Validate generated JSON with `synapsor-runner contract validate`.
@@ -138,10 +138,13 @@ synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapso
138
138
  You can also compile from the SQL-like authoring layer:
139
139
 
140
140
  ```bash
141
- synapsor-runner dsl validate ./contract.synapsor
142
- synapsor-runner dsl compile ./contract.synapsor --out ./synapsor.contract.json --strict
141
+ synapsor-runner dsl validate ./contract.synapsor.sql
142
+ synapsor-runner dsl compile ./contract.synapsor.sql --out ./synapsor.contract.json --strict
143
143
  ```
144
144
 
145
+ `.synapsor.sql` is the preferred editor-friendly source filename. Existing
146
+ `.synapsor` files remain valid and compile to equivalent canonical JSON.
147
+
145
148
  ## Bundle For Local Runner
146
149
 
147
150
  Cloud/exported or hand-written contracts can become a local Runner bundle:
@@ -56,8 +56,9 @@ Write credential for direct `sql_update`:
56
56
 
57
57
  - can update only the allowed business columns;
58
58
  - cannot modify primary-key or tenant columns;
59
- - can create/write the `synapsor_writeback_receipts` table, or the table is
60
- pre-created and granted by an administrator;
59
+ - can `SELECT`/`INSERT`/`UPDATE` the administrator-created
60
+ `synapsor_writeback_receipts` table;
61
+ - does not need schema `CREATE` during doctor or apply;
61
62
  - is never exposed to MCP clients.
62
63
 
63
64
  Example config:
@@ -81,7 +82,7 @@ worker flows that do not pass a local config.
81
82
  ## Receipt Table
82
83
 
83
84
  Direct SQL writeback stores idempotency receipts in the source database. Runner
84
- creates this table if allowed:
85
+ expects an administrator to create this table before steady-state operation:
85
86
 
86
87
  ```sql
87
88
  CREATE TABLE IF NOT EXISTS synapsor_writeback_receipts (...);
@@ -97,10 +98,9 @@ synapsor-runner doctor --config synapsor.runner.json --check-writeback
97
98
 
98
99
  For MySQL, replace `postgres` with `mysql`.
99
100
 
100
- If the writer should not create application-schema tables, pre-create the
101
- receipt table with an administrator role, grant only the needed receipt-table
102
- permissions to the writer, or use an app-owned executor that stores receipts in
103
- your application boundary.
101
+ Grant only receipt-table `SELECT`/`INSERT`/`UPDATE` and schema usage to the
102
+ writer; schema `CREATE` is not required by doctor or apply. Use an app-owned
103
+ executor when receipt storage belongs inside your application boundary.
104
104
 
105
105
  ## Direct Writeback Vs App-Owned Executor
106
106
 
@@ -286,4 +286,3 @@ Before promoting a package or calling a build production-candidate:
286
286
  The release gate should cover typecheck, focused tests, packed-package install,
287
287
  quick demo, own-db fixture, MCP stdio/HTTP checks, direct writeback,
288
288
  app-owned executor paths, package dry-run, and docs/package consistency.
289
-
@@ -12,9 +12,38 @@ for the Synapsor Cloud CLI.
12
12
 
13
13
  ## Unreleased
14
14
 
15
- Prepared package version: `@synapsor/runner@0.1.12`. The already-published
16
- `@synapsor/spec@0.1.4` and `@synapsor/dsl@0.1.4` do not change and must not be
17
- republished for this release.
15
+ ## 0.1.16
16
+
17
+ ### Fleet-Lab Runner Hardening
18
+
19
+ - Preserves Postgres microseconds in proposal conflict guards and proves normal
20
+ `now()` rows apply exactly once while genuinely stale rows conflict.
21
+ - Allows a new proposal after conflict without deleting or rewriting the old
22
+ proposal, receipt, or replay history.
23
+ - Returns semantic active-proposal errors and rejects non-primary DSL lookups.
24
+ - Removes schema-creation requirements from steady-state writeback, aligns audit
25
+ paths and JSON Schema with contract configs, and creates local ledgers with
26
+ owner-only POSIX permissions.
27
+ - Adds complete DSL, Runner config, and ledger inspection/security references.
28
+
29
+ Prepared package versions: `@synapsor/dsl@0.1.6` and
30
+ `@synapsor/runner@0.1.16`. `@synapsor/spec@0.1.4` remains unchanged.
31
+
32
+ ## 0.1.15
33
+
34
+ ### Editor-Friendly DSL Source Files
35
+
36
+ - Prefers `.synapsor.sql` for DSL source files so editors can provide generic
37
+ SQL highlighting; `.synapsor` remains supported for compatibility.
38
+ - The filename suffix does not change DSL semantics or generated canonical JSON.
39
+ - Stages `@synapsor/dsl@0.1.5` and `@synapsor/runner@0.1.15`; `@synapsor/spec`
40
+ remains `0.1.4`.
41
+
42
+ Prepared package versions: `@synapsor/dsl@0.1.5` and
43
+ `@synapsor/runner@0.1.15`. The already-published `@synapsor/spec@0.1.4` does
44
+ not change and must not be republished for this release.
45
+
46
+ ## 0.1.12
18
47
 
19
48
  ### Runner Version Invocation
20
49
 
@@ -390,9 +419,9 @@ republished for this release.
390
419
  `SYNAPSOR_DATABASE_WRITE_URL`.
391
420
  - `SYNAPSOR_DATABASE_URL` is accepted only as a legacy fallback for older
392
421
  direct worker/apply flows without a local config.
393
- - Direct SQL writeback creates or writes `synapsor_writeback_receipts` for
394
- idempotency and replay. The trusted writer needs permission for that receipt
395
- table, or an administrator must pre-create the table and grant access.
422
+ - Direct SQL writeback writes `synapsor_writeback_receipts` for idempotency and
423
+ replay. Current releases require an administrator-created table and grant the
424
+ trusted writer table access without schema `CREATE`.
396
425
  - Use `synapsor-runner writeback doctor`, `writeback migration`, and
397
426
  `writeback grants` to inspect and prepare the direct writeback path.
398
427
  - Use app-owned `http_handler` or `command_handler` executors for rich writes
@@ -0,0 +1,194 @@
1
+ # Runner Config Reference
2
+
3
+ `synapsor.runner.json` wires portable reviewed contracts to one local runtime.
4
+ It contains environment-variable names and fixed identifiers, never database
5
+ URLs, passwords, bearer tokens, prompts, or model-selected tenant authority.
6
+
7
+ Validate before serving:
8
+
9
+ ```bash
10
+ synapsor-runner config validate --config ./synapsor.runner.json
11
+ ```
12
+
13
+ Editor schema:
14
+
15
+ ```text
16
+ schemas/synapsor.runner.schema.json
17
+ ```
18
+
19
+ Unknown keys fail when `strict` is true (the default).
20
+
21
+ ## Top-level keys
22
+
23
+ | Key | Required | Meaning |
24
+ | --- | --- | --- |
25
+ | `version` | Yes | Must be `1`. |
26
+ | `mode` | Yes | `read_only`, `shadow`, `review`, or `cloud`. |
27
+ | `result_format` | No | `1` legacy or `2` stable `ok/summary/data/proposal/error` envelope. Default `1`. |
28
+ | `strict` | No | Reject unknown config keys. Default `true`. |
29
+ | `storage` | Local | Local SQLite ledger. |
30
+ | `sources` | Local | Named Postgres/MySQL source wiring. |
31
+ | `trusted_context` | Conditional | Default trusted tenant/principal binding. |
32
+ | `contexts` | No | Named trusted contexts referenced by capabilities/contracts. |
33
+ | `contracts` | No | Portable contract file paths. Preferred for reviewed authoring. |
34
+ | `capabilities` | Conditional | Embedded compatibility capabilities; may be `[]` with `contracts`. |
35
+ | `policies` | No | Embedded reviewed policies; contract policies merge into the same catalog. |
36
+ | `approvals` | No | Local approval overrides. |
37
+ | `executors` | No | App-owned writeback wiring. |
38
+ | `cloud` | Cloud mode | Scoped Cloud adapter configuration. |
39
+
40
+ ## Path resolution
41
+
42
+ - `contracts` entries resolve relative to the directory containing the config
43
+ file. Every command uses this rule, including audit, validate, doctor, tools,
44
+ smoke, MCP serve, propose, and apply.
45
+ - `storage.sqlite_path` is resolved by the Runner process working directory.
46
+ Pass an absolute path when an MCP client launches Runner from another CWD.
47
+ - Executor paths/URLs come from environment variables, not relative contract
48
+ content.
49
+
50
+ ## Storage
51
+
52
+ ```json
53
+ { "storage": { "sqlite_path": "./.synapsor/local.db" } }
54
+ ```
55
+
56
+ The ledger stores proposals, visible evidence copies, query audit, approvals,
57
+ receipts, events, and replay. New POSIX stores are owner-only (`0600`). Protect
58
+ the file like a database extract; see [Store Lifecycle](store-lifecycle.md).
59
+
60
+ ## Sources
61
+
62
+ ```json
63
+ {
64
+ "sources": {
65
+ "billing_postgres": {
66
+ "engine": "postgres",
67
+ "read_url_env": "BILLING_POSTGRES_READ_URL",
68
+ "write_url_env": "BILLING_POSTGRES_WRITE_URL",
69
+ "read_only": false,
70
+ "statement_timeout_ms": 3000
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ `engine` is `postgres` or `mysql`. `read_url_env` is required. Use a
77
+ least-privilege read credential. `write_url_env` is optional unless direct SQL
78
+ writeback must apply; it should name a separate restricted writer. `read_only:
79
+ true` forbids direct SQL writeback. `statement_timeout_ms` is a positive read
80
+ timeout. `ssl` carries adapter-specific reviewed SSL options when used.
81
+
82
+ A contract's `SOURCE billing_postgres` must exactly match a `sources` key.
83
+
84
+ ## Trusted context
85
+
86
+ ```json
87
+ {
88
+ "trusted_context": {
89
+ "provider": "environment",
90
+ "values": {
91
+ "tenant_id_env": "SYNAPSOR_TENANT_ID",
92
+ "principal_env": "SYNAPSOR_PRINCIPAL"
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ Providers are `environment`, `static_dev`, `http_claims`, and `cloud_session`.
99
+ `static_dev` is only for local fixtures. Named `contexts` use the same shape.
100
+ Capabilities may reference a context by name. The model never receives tenant
101
+ or principal as an overridable argument.
102
+
103
+ ## Contracts and embedded capabilities
104
+
105
+ ```json
106
+ {
107
+ "contracts": ["./billing.contract.json"],
108
+ "capabilities": []
109
+ }
110
+ ```
111
+
112
+ Contracts are normalized `@synapsor/spec` JSON. Runner merges their contexts,
113
+ capabilities, and policies into one runtime catalog. Duplicate names across
114
+ embedded config and contracts fail; there is no silent shadowing.
115
+
116
+ Embedded capabilities remain supported for generated/legacy configs. Their
117
+ fields are documented in the JSON Schema and
118
+ [Capability Authoring](capability-authoring.md): fixed target, args, primary-key
119
+ lookup, visible fields, evidence, patch allowlist, bounds/transitions, conflict
120
+ guard, approval, and writeback mode.
121
+
122
+ ## Executors
123
+
124
+ ```json
125
+ {
126
+ "executors": {
127
+ "billing_handler": {
128
+ "type": "http_handler",
129
+ "url_env": "BILLING_HANDLER_URL",
130
+ "method": "POST",
131
+ "auth": {
132
+ "type": "bearer_env",
133
+ "token_env": "BILLING_HANDLER_TOKEN"
134
+ },
135
+ "signing_secret_env": "BILLING_HANDLER_SIGNING_SECRET",
136
+ "timeout_ms": 5000
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ Types are `sql_update`, `http_handler`, and `command_handler`. HTTP handlers use
143
+ `url_env`, optional `POST|PUT|PATCH`, bearer auth, signing secret, and timeout.
144
+ Command handlers use `command_env` and timeout. Secrets stay in the environment.
145
+ See [Writeback Executors](writeback-executors.md).
146
+
147
+ ## Policies and approvals
148
+
149
+ `policies` is an array of reviewed policy objects. Local approval policies use
150
+ `kind: "approval"` and numeric rules such as `{ "field": "amount_cents",
151
+ "max": 2500 }`. `approvals.disable_auto_approval: true` disables local policy
152
+ auto-approval without changing the reviewed contract. Approval never becomes an
153
+ MCP tool.
154
+
155
+ ## Cloud mode
156
+
157
+ Cloud mode omits local sources/capabilities and requires:
158
+
159
+ ```json
160
+ {
161
+ "version": 1,
162
+ "mode": "cloud",
163
+ "cloud": {
164
+ "base_url_env": "SYNAPSOR_CLOUD_BASE_URL",
165
+ "runner_token_env": "SYNAPSOR_RUNNER_TOKEN",
166
+ "adapter_id": "mcp.billing",
167
+ "runner_id": "runner_local_1",
168
+ "project_id": "project_123",
169
+ "engines": ["postgres"],
170
+ "capabilities": ["adapter:read", "adapter:invoke"],
171
+ "session": {}
172
+ }
173
+ }
174
+ ```
175
+
176
+ `base_url_env`, `runner_token_env`, and `adapter_id` are required. Optional keys
177
+ are `runner_id`, `runner_version`, `project_id`, `source_id`, `engines`, scoped
178
+ capability permissions, and trusted session metadata.
179
+
180
+ ## Direct SQL readiness
181
+
182
+ An administrator must apply `writeback migration` once. The steady-state writer
183
+ needs target-table SELECT/allowed UPDATE plus receipt-table
184
+ SELECT/INSERT/UPDATE; it does not need schema CREATE.
185
+
186
+ ```bash
187
+ synapsor-runner writeback migration --engine postgres --schema synapsor
188
+ synapsor-runner writeback grants --engine postgres \
189
+ --schema synapsor --writer-role synapsor_writer
190
+ synapsor-runner doctor --config ./synapsor.runner.json --check-writeback
191
+ ```
192
+
193
+ The doctor probe uses a rolled-back receipt insert and target-table check. It
194
+ does not mutate business rows.
@@ -66,11 +66,11 @@ outside the model-facing MCP server and verifies:
66
66
  If any authority check cannot be verified, the write fails closed.
67
67
 
68
68
  For direct SQL writeback, the writer connection is the env var named by the
69
- source `write_url_env` in `synapsor.runner.json`. Direct SQL writeback also
70
- creates or writes `synapsor_writeback_receipts` for idempotency and replay, so
71
- the writer needs permission for that receipt table or an administrator must
72
- pre-create and grant it. If your database policy forbids Runner-managed receipt
73
- tables, use an app-owned `http_handler` or `command_handler` executor instead.
69
+ source `write_url_env` in `synapsor.runner.json`. Direct SQL writeback writes an
70
+ administrator-created `synapsor_writeback_receipts` table for idempotency and
71
+ replay. The writer needs `SELECT`/`INSERT`/`UPDATE` on that table, but not schema
72
+ `CREATE`. If your database policy forbids the receipt table, use an app-owned
73
+ `http_handler` or `command_handler` executor instead.
74
74
 
75
75
  When a capability uses an `http_handler` or `command_handler` executor, the
76
76
  same approval boundary applies. The runner sends a structured proposal/job
@@ -9,6 +9,44 @@ Default path:
9
9
  ./.synapsor/local.db
10
10
  ```
11
11
 
12
+ ## Data sensitivity and permissions
13
+
14
+ The ledger contains copies of the business fields allowed by each capability:
15
+ visible before/after evidence, proposal diffs, actor/tenant metadata, query
16
+ fingerprints, approvals, receipts, and replay events. Treat it like a scoped
17
+ database extract, not disposable cache data.
18
+
19
+ Runner creates new POSIX store files with owner-only mode `0600` and tightens an
20
+ owned existing store when it opens it. On Windows, use the operating system's
21
+ file ACLs. Use encrypted disks, restrict OS accounts, and set a retention policy
22
+ appropriate for the visible business data.
23
+
24
+ `KEEP OUT` fields and redacted query parameters are not written to normal
25
+ evidence records. They do not make the rest of the ledger non-sensitive.
26
+
27
+ Direct SQLite inspection is supported **read-only** for independent verification:
28
+
29
+ ```bash
30
+ sqlite3 -readonly ./.synapsor/local.db '.tables'
31
+ ```
32
+
33
+ Do not mutate the database directly. Its internal tables may change between
34
+ releases and are not a public storage API; use Runner commands for automation.
35
+
36
+ ## Inspect the ledger
37
+
38
+ | Question | Command |
39
+ | --- | --- |
40
+ | What did the model propose? | `synapsor-runner proposals show <proposal-id> --details` |
41
+ | What data supported it? | `synapsor-runner evidence list --proposal <proposal-id>` then `evidence show <evidence-id> --details` |
42
+ | What query was run? | `synapsor-runner query-audit list --proposal <proposal-id>` |
43
+ | Who approved or rejected it? | `synapsor-runner proposals show <proposal-id> --details` |
44
+ | Did guarded writeback apply? | `synapsor-runner receipts list --proposal <proposal-id>` |
45
+ | What happened end to end? | `synapsor-runner replay show --proposal <proposal-id> --details` |
46
+ | What happened to one object? | `synapsor-runner activity search --object invoice:INV-3001` |
47
+ | What are the latest events? | `synapsor-runner events tail` |
48
+ | How large is the store? | `synapsor-runner store stats --store ./.synapsor/local.db` |
49
+
12
50
  ## Server leases
13
51
 
14
52
  MCP server modes write a small lease file next to the store:
@@ -65,9 +65,9 @@ npx -y -p @synapsor/runner synapsor-runner writeback grants --engine postgres --
65
65
  ```
66
66
 
67
67
  `writeback doctor --check-db` connects with the configured writer credential and
68
- checks the receipt table path. That check can create the receipt table if the
69
- writer has `CREATE`, so run it only against staging/disposable databases or
70
- after reviewing the printed migration/grants.
68
+ checks the pre-created receipt table path in a rolled-back transaction. Apply
69
+ the printed migration as an administrator first; the steady-state writer needs
70
+ table `SELECT`/`INSERT`/`UPDATE`, not schema `CREATE`.
71
71
 
72
72
  ## `http_handler`
73
73