@synapsor/runner 1.6.2 → 1.6.4

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 (116) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +141 -2
  3. package/CONTRIBUTING.md +10 -3
  4. package/README.md +65 -83
  5. package/SECURITY.md +14 -2
  6. package/THREAT_MODEL.md +64 -4
  7. package/dist/authoring.mjs +151 -16
  8. package/dist/cli.d.ts +31 -3
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/local-ui.d.ts +145 -1
  11. package/dist/local-ui.d.ts.map +1 -1
  12. package/dist/runner.mjs +37488 -19009
  13. package/dist/runtime.mjs +4056 -235
  14. package/dist/shadow.mjs +2423 -65
  15. package/docs/README.md +36 -2
  16. package/docs/agent-guided-setup.md +239 -0
  17. package/docs/aggregate-reads.md +14 -5
  18. package/docs/app-owned-executors.md +5 -6
  19. package/docs/approval-roles-and-operator-identity.md +353 -0
  20. package/docs/auto-boundary-and-scoped-explore.md +89 -11
  21. package/docs/capability-authoring.md +21 -2
  22. package/docs/client-recipes.md +1 -1
  23. package/docs/cloud-mode.md +7 -7
  24. package/docs/conformance.md +6 -3
  25. package/docs/current-scope.md +32 -2
  26. package/docs/cursor-plugin.md +3 -3
  27. package/docs/database-enforced-scope.md +6 -0
  28. package/docs/dsl-json-parity.md +75 -0
  29. package/docs/dsl-reference.md +22 -1
  30. package/docs/fresh-developer-usability.md +155 -80
  31. package/docs/getting-started-own-database.md +45 -44
  32. package/docs/guarded-crud-writeback.md +19 -0
  33. package/docs/guided-onboarding.md +399 -0
  34. package/docs/human-attention-notifications.md +367 -0
  35. package/docs/limitations.md +49 -13
  36. package/docs/local-mode.md +36 -22
  37. package/docs/mcp-audit.md +14 -14
  38. package/docs/mcp-client-setup.md +11 -14
  39. package/docs/mcp-clients.md +1 -1
  40. package/docs/migrating-to-synapsor-spec.md +42 -0
  41. package/docs/openai-agents-sdk.md +2 -2
  42. package/docs/production.md +39 -0
  43. package/docs/proposal-evidence-freshness.md +7 -7
  44. package/docs/recipes.md +6 -6
  45. package/docs/release-notes.md +144 -4
  46. package/docs/release-policy.md +20 -7
  47. package/docs/reversible-change-sets.md +1 -1
  48. package/docs/reviewed-database-views.md +132 -0
  49. package/docs/reviewed-relationships.md +245 -0
  50. package/docs/rfcs/006-reviewed-reversible-change-sets.md +1 -1
  51. package/docs/runner-bundles.md +7 -7
  52. package/docs/runner-config-reference.md +132 -0
  53. package/docs/running-a-runner-fleet.md +16 -1
  54. package/docs/schema-api-candidates.md +1 -1
  55. package/docs/security-boundary.md +54 -0
  56. package/docs/store-lifecycle.md +20 -1
  57. package/docs/supervised-automatic-apply.md +267 -0
  58. package/docs/troubleshooting-first-run.md +85 -10
  59. package/docs/use-your-own-database.md +6 -4
  60. package/docs/workbench-ask.md +279 -0
  61. package/docs/writeback-executors.md +7 -7
  62. package/examples/auto-boundary-churn/README.md +1 -1
  63. package/examples/community-solar-clean-room/README.md +7 -0
  64. package/examples/community-solar-clean-room/docker-compose.yml +16 -0
  65. package/examples/community-solar-clean-room/package.json +15 -0
  66. package/examples/community-solar-clean-room/prisma/schema.prisma +171 -0
  67. package/examples/community-solar-clean-room/seed/postgres.sql +571 -0
  68. package/examples/fitflow-guided-onboarding/README.md +43 -0
  69. package/examples/fitflow-guided-onboarding/app/page.tsx +8 -0
  70. package/examples/fitflow-guided-onboarding/docker-compose.yml +16 -0
  71. package/examples/fitflow-guided-onboarding/package.json +18 -0
  72. package/examples/fitflow-guided-onboarding/prisma/schema.prisma +98 -0
  73. package/examples/fitflow-guided-onboarding/seed/postgres.sql +401 -0
  74. package/examples/openai-agents-http/Makefile +1 -1
  75. package/examples/openai-agents-http/README.md +1 -1
  76. package/examples/openai-agents-stdio/Makefile +1 -1
  77. package/examples/openai-agents-stdio/README.md +2 -2
  78. package/examples/openai-agents-stdio/agent.py +1 -4
  79. package/examples/operator-oidc/issuer.mjs +188 -0
  80. package/examples/reference-support-billing-app/README.md +16 -16
  81. package/examples/retail-clean-room/README.md +7 -0
  82. package/examples/retail-clean-room/docker-compose.yml +16 -0
  83. package/examples/retail-clean-room/package.json +9 -0
  84. package/examples/retail-clean-room/prisma/schema.prisma +239 -0
  85. package/examples/retail-clean-room/seed/postgres.sql +781 -0
  86. package/examples/retail-clean-room/view-recipe/average-retained-revenue.synapsor.sql +21 -0
  87. package/examples/retail-clean-room/view-recipe/synapsor.runner.json +25 -0
  88. package/examples/support-plan-credit/README.md +6 -2
  89. package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +1 -4
  90. package/examples/support-plan-credit/mcp-client-examples/claude-desktop.json +1 -4
  91. package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +1 -4
  92. package/examples/support-plan-credit/mcp-client-examples/cursor-global.mcp.json +1 -4
  93. package/examples/support-plan-credit/mcp-client-examples/cursor-project.mcp.json +1 -4
  94. package/examples/support-plan-credit/mcp-client-examples/generic-stdio.json +1 -4
  95. package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +1 -1
  96. package/examples/support-plan-credit/mcp-client-examples/google-adk.py +1 -1
  97. package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +1 -1
  98. package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +1 -1
  99. package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
  100. package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +1 -4
  101. package/fixtures/compatibility/published-1.6.3/manifest.json +76 -0
  102. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
  103. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
  104. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
  105. package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
  106. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
  107. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
  108. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
  109. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
  110. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
  111. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
  112. package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
  113. package/llms.txt +10 -5
  114. package/package.json +11 -3
  115. package/schemas/schema-candidate-review.schema.json +42 -0
  116. package/schemas/synapsor.runner.schema.json +227 -4
@@ -0,0 +1,353 @@
1
+ # Approval Roles And Verified Operator Identity
2
+
3
+ This guide explains how a role written in a Synapsor capability becomes a
4
+ verified human approval. The short version is:
5
+
6
+ ```text
7
+ Contract says who may approve
8
+ -> identity provider says who the operator is and which groups they hold
9
+ -> Runner verifies a fresh token and exact role
10
+ -> ledger records the exact decision without storing the bearer token
11
+ -> a separate verified operator authorizes apply
12
+ ```
13
+
14
+ Approval and apply are outside the model-facing MCP tool surface. An agent
15
+ cannot supply an operator token, select its own role, approve a proposal, or
16
+ commit a write.
17
+
18
+ ## What `APPROVAL ROLE` Means
19
+
20
+ This public DSL:
21
+
22
+ ```sql
23
+ CREATE CAPABILITY membership.freeze_membership
24
+ ...
25
+ APPROVAL ROLE membership_reviewer
26
+ ...
27
+ ;
28
+ ```
29
+
30
+ means that an operator approving this capability's proposal must have the exact
31
+ role string `membership_reviewer` in a verified identity.
32
+
33
+ `membership_reviewer` is an author-chosen Synapsor contract role. It is not:
34
+
35
+ - a PostgreSQL role;
36
+ - an operating-system user or group;
37
+ - an MCP or model role;
38
+ - an API key or secret;
39
+ - permission to apply the write.
40
+
41
+ The contract fixes the required role. The model cannot put a different role in
42
+ a tool argument.
43
+
44
+ ## The Complete Identity Chain
45
+
46
+ 1. A contract author writes `APPROVAL ROLE membership_reviewer`.
47
+ 2. An identity administrator maps real people to an IdP group. For example,
48
+ members of `example-membership-reviewers` receive
49
+ `membership_reviewer` in the token's `groups` claim.
50
+ 3. Runner's `operator_identity` configuration fixes the token source, allowed
51
+ algorithm, public-key source, issuer, audience, subject claim, roles claim,
52
+ and apply roles.
53
+ 4. For every approval, Runner reads a fresh token from environment, a protected
54
+ token file, or stdin.
55
+ 5. Runner verifies the asymmetric algorithm, signature and JWKS key, issuer,
56
+ audience, `exp`, and `nbf`. It then reads a safe subject and the configured
57
+ roles claim.
58
+ 6. Runner requires an exact role match. `membership_reviewer_backup` does not
59
+ satisfy `membership_reviewer`.
60
+ 7. The approval is bound to the immutable proposal ID, version, and hash, the
61
+ action `approve`, the verified subject, and the decision time.
62
+ 8. Runner stores the verified identity metadata and an attested decision proof.
63
+ It never stores the bearer token.
64
+ 9. Apply is a second operator decision. A fresh verified identity must satisfy
65
+ `operator_identity.apply_roles`; approval does not imply commit authority.
66
+
67
+ At apply time Runner also verifies the stored approval proof against the exact
68
+ proposal. A changed proposal ID, version, hash, role, subject, decision, or
69
+ attestation fails before source mutation.
70
+
71
+ ## Development-Only Identity
72
+
73
+ For one-user local development, `dev_env` preserves the lightweight workflow:
74
+
75
+ ```json
76
+ {
77
+ "operator_identity": {
78
+ "provider": "dev_env",
79
+ "actor_env": "SYNAPSOR_OPERATOR_ID",
80
+ "roles_env": "SYNAPSOR_OPERATOR_ROLES",
81
+ "apply_roles": ["writeback_operator"]
82
+ }
83
+ }
84
+ ```
85
+
86
+ ```bash
87
+ export SYNAPSOR_OPERATOR_ID="local-reviewer"
88
+ export SYNAPSOR_OPERATOR_ROLES="membership_reviewer,writeback_operator"
89
+
90
+ synapsor-runner proposals approve latest \
91
+ --config ./synapsor.runner.json \
92
+ --store ./.synapsor/local.db \
93
+ --yes
94
+ ```
95
+
96
+ `dev_env` is explicitly unverified. Environment text is trusted as entered. Do
97
+ not use it for a shared Runner, production, or a decision that must prove who
98
+ approved it. Use `jwt_oidc` or `signed_key` there.
99
+
100
+ ## Production-Style OIDC Configuration
101
+
102
+ The following block is parsed and used by the packed OIDC integration test.
103
+ The simulated issuer uses the same shape, but this is not Okta, Entra, Auth0,
104
+ or any other vendor certification.
105
+
106
+ <!-- synapsor-oidc-operator-config:start -->
107
+ ```json
108
+ {
109
+ "provider": "jwt_oidc",
110
+ "apply_roles": ["writeback_operator"],
111
+ "token_env": "SYNAPSOR_OPERATOR_TOKEN",
112
+ "roles_claim": "groups",
113
+ "subject_claim": "sub",
114
+ "attestation_secret_env": "SYNAPSOR_OPERATOR_ATTESTATION_SECRET",
115
+ "algorithms": ["RS256"],
116
+ "jwks_url_env": "SYNAPSOR_OPERATOR_JWKS_URL",
117
+ "issuer": "https://identity.example.test/oidc",
118
+ "audience": "synapsor-operators",
119
+ "clock_skew_seconds": 0,
120
+ "jwks_cache_seconds": 60,
121
+ "jwks_cooldown_seconds": 1,
122
+ "fetch_timeout_ms": 2000,
123
+ "max_response_bytes": 8192
124
+ }
125
+ ```
126
+ <!-- synapsor-oidc-operator-config:end -->
127
+
128
+ Place that object at `operator_identity` in `synapsor.runner.json`. The
129
+ configuration uses environment-variable names, not their secret values.
130
+
131
+ The IdP mapping for this example is:
132
+
133
+ | IdP group | JWT `groups` value | Synapsor purpose |
134
+ | --- | --- | --- |
135
+ | `example-membership-reviewers` | `membership_reviewer` | Satisfies the capability's exact `APPROVAL ROLE`. |
136
+ | `example-writeback-operators` | `writeback_operator` | Satisfies the independent `apply_roles` gate. |
137
+
138
+ Configure this mapping in the IdP. Runner does not infer it from database roles
139
+ or group names.
140
+
141
+ ### What Each Setting Does
142
+
143
+ | Setting | Meaning |
144
+ | --- | --- |
145
+ | `algorithms` | Exact asymmetric algorithms Runner accepts. OIDC operator identity supports `RS256` and `ES256`; do not infer this from the token header. |
146
+ | `jwks_url_env` | Environment variable containing the IdP's public JWKS URL. Remote URLs must use HTTPS; HTTP is accepted only on loopback for development. |
147
+ | `issuer` / `audience` | Values Runner requires in `iss` and `aud`. |
148
+ | `subject_claim` | Verified top-level claim used as the operator identity. |
149
+ | `roles_claim` | Verified top-level claim containing exact Synapsor role strings. |
150
+ | `token_env` | Environment variable holding the short-lived operator bearer token for this command. |
151
+ | `attestation_secret_env` | Environment variable holding at least 32 bytes of Runner-side key material used to attest the redacted stored decision. |
152
+ | `apply_roles` | Roles accepted for the separate apply decision. |
153
+
154
+ The attestation secret is not the OIDC token and not an IdP client secret.
155
+ Runner uses it locally to make the stored, token-free identity proof
156
+ tamper-evident. Every trusted process that verifies the same ledger needs the
157
+ same protected value. Keep it out of source control, MCP configuration, logs,
158
+ and model context.
159
+
160
+ ## Run The Local OIDC/JWKS Fixture
161
+
162
+ The npm package includes a synthetic localhost-only issuer. It generates
163
+ ephemeral RS256 private keys in memory, serves only public keys at `/jwks`, and
164
+ mints fixed test identities. It must never be used as a real identity provider.
165
+
166
+ In terminal 1:
167
+
168
+ ```bash
169
+ export SYNAPSOR_EXAMPLE_OIDC_PORT=9411
170
+ node ./node_modules/@synapsor/runner/examples/operator-oidc/issuer.mjs
171
+ ```
172
+
173
+ It prints one JSON object describing:
174
+
175
+ ```text
176
+ JWKS: http://127.0.0.1:9411/jwks
177
+ Issuer: https://identity.example.test/oidc
178
+ Audience: synapsor-operators
179
+ ```
180
+
181
+ The server holds the private keys only in memory. Stop it after the walkthrough.
182
+
183
+ In terminal 2, from a Synapsor project that has one pending
184
+ `membership_reviewer` proposal:
185
+
186
+ ```bash
187
+ export SYNAPSOR_OPERATOR_JWKS_URL="http://127.0.0.1:9411/jwks"
188
+ export SYNAPSOR_OPERATOR_ATTESTATION_SECRET="$(openssl rand -base64 32)"
189
+
190
+ export SYNAPSOR_OPERATOR_TOKEN="$(
191
+ curl -fsS http://127.0.0.1:9411/token/reviewer |
192
+ node -pe 'JSON.parse(require("node:fs").readFileSync(0,"utf8")).access_token'
193
+ )"
194
+
195
+ synapsor-runner proposals approve latest \
196
+ --config ./synapsor.runner.json \
197
+ --store ./.synapsor/local.db \
198
+ --yes \
199
+ --json
200
+
201
+ unset SYNAPSOR_OPERATOR_TOKEN
202
+ ```
203
+
204
+ The token is supplied through the environment and is not a command-line
205
+ argument. For a real deployment, inject a short-lived token through a protected
206
+ process environment, protected token file, or stdin. Never commit it.
207
+
208
+ The fixture's apply identity uses a rotated key. Keep the old and new public
209
+ keys overlapped during rotation:
210
+
211
+ ```bash
212
+ curl -fsS -X POST http://127.0.0.1:9411/rotate
213
+
214
+ export SYNAPSOR_OPERATOR_TOKEN="$(
215
+ curl -fsS http://127.0.0.1:9411/token/applier |
216
+ node -pe 'JSON.parse(require("node:fs").readFileSync(0,"utf8")).access_token'
217
+ )"
218
+
219
+ synapsor-runner apply latest \
220
+ --config ./synapsor.runner.json \
221
+ --store ./.synapsor/local.db \
222
+ --json
223
+
224
+ unset SYNAPSOR_OPERATOR_TOKEN
225
+ ```
226
+
227
+ This second token has `writeback_operator`, not
228
+ `membership_reviewer`. It authorizes apply only after Runner verifies the
229
+ stored approval and all guarded-write prerequisites.
230
+
231
+ ### Token File Or Stdin
232
+
233
+ Configure exactly one token source.
234
+
235
+ For a protected token file, replace `token_env` with:
236
+
237
+ ```json
238
+ {
239
+ "token_file_env": "SYNAPSOR_OPERATOR_TOKEN_FILE"
240
+ }
241
+ ```
242
+
243
+ Set the environment variable to a mode-`0600` file outside the repository.
244
+ Delete the file after the decision.
245
+
246
+ For stdin, replace `token_env` with:
247
+
248
+ ```json
249
+ {
250
+ "token_stdin": true
251
+ }
252
+ ```
253
+
254
+ Use `--yes` so confirmation does not compete for stdin:
255
+
256
+ ```bash
257
+ printf '%s\n' "$SHORT_LIVED_OPERATOR_TOKEN" |
258
+ synapsor-runner proposals approve "$PROPOSAL_ID" \
259
+ --config ./synapsor.runner.json \
260
+ --store ./.synapsor/local.db \
261
+ --yes
262
+ ```
263
+
264
+ Do not pass a token as a CLI argument.
265
+
266
+ ## What The Ledger Stores
267
+
268
+ Inspect the full lifecycle without copying an opaque ID:
269
+
270
+ ```bash
271
+ synapsor-runner replay show latest \
272
+ --config ./synapsor.runner.json \
273
+ --store ./.synapsor/local.db \
274
+ --json
275
+ ```
276
+
277
+ The approval record has this shape:
278
+
279
+ ```json
280
+ {
281
+ "proposal_version": 1,
282
+ "proposal_hash": "sha256:...",
283
+ "approver": "reviewer@example.test",
284
+ "status": "approved",
285
+ "identity": {
286
+ "provider": "jwt_oidc",
287
+ "verified": true,
288
+ "subject": "reviewer@example.test",
289
+ "roles": ["membership_reviewer"],
290
+ "key_id": "fitflow-key-1",
291
+ "algorithm": "RS256",
292
+ "issuer": "https://identity.example.test/oidc",
293
+ "decision": {
294
+ "schema_version": "synapsor.operator-decision.v1",
295
+ "action": "approve",
296
+ "proposal_id": "wrp_...",
297
+ "proposal_version": 1,
298
+ "proposal_hash": "sha256:...",
299
+ "subject": "reviewer@example.test",
300
+ "issued_at": "..."
301
+ },
302
+ "decision_hash": "sha256:...",
303
+ "signature": "...",
304
+ "integrity_hash": "sha256:..."
305
+ }
306
+ }
307
+ ```
308
+
309
+ `signature` is Runner's HMAC attestation over the redacted verified identity
310
+ and exact decision. It is not the original OIDC JWT signature. The bearer token
311
+ is absent.
312
+
313
+ The replay also contains a `writeback_authorized` event for the independently
314
+ verified apply identity and the normal guarded-write receipt.
315
+
316
+ ## JWKS Caching And Key Rotation
317
+
318
+ For a long-running Runner process, remote JWKS keys are held in memory for
319
+ `jwks_cache_seconds` (default 600 seconds). An unknown `kid` may trigger a
320
+ bounded refresh after `jwks_cooldown_seconds` (default 30 seconds). Fetches have
321
+ a timeout and maximum response size, reject redirects, and accept public keys
322
+ only. A one-shot CLI command starts with an empty in-memory cache.
323
+
324
+ During rotation:
325
+
326
+ 1. Publish the new public key while retaining the old key.
327
+ 2. Wait at least the configured cache lifetime plus expected clock skew.
328
+ 3. Start issuing tokens with the new `kid`.
329
+ 4. Keep the overlap long enough for long-running processes to refresh.
330
+ 5. Remove the old key only after old tokens and caches have expired.
331
+
332
+ Runner's verifier tests exercise an in-process unknown-`kid` refresh. The packed
333
+ approval integration uses the old key for approval, publishes an overlapping
334
+ new key, and uses the new key for the independent apply decision.
335
+
336
+ ## Fail-Closed Troubleshooting
337
+
338
+ | Failure | What Runner does | Remediation |
339
+ | --- | --- | --- |
340
+ | Missing or similar role | Refuses the decision; proposal stays pending. | Map the exact contract role into the configured roles claim. Do not rename the role at runtime. |
341
+ | Wrong issuer or audience | Rejects JWT verification. | Match the exact IdP issuer and application audience. |
342
+ | Unknown `kid` | Refreshes only within the bounded JWKS policy, then rejects if no public key matches. | Publish overlapping keys and wait for the cooldown/cache policy. |
343
+ | Invalid signature | Rejects the token. | Obtain a fresh token from the configured issuer; do not bypass verification. |
344
+ | Expired or not-yet-valid token | Rejects the token. | Fix clock synchronization and obtain a currently valid token. Keep clock skew narrow. |
345
+ | Unsafe subject or malformed roles | Refuses identity resolution. | Emit a safe top-level string subject and an array or delimited string of safe role names. |
346
+ | JWKS endpoint unavailable | Fails closed when a required key cannot be resolved. | Restore HTTPS/network/DNS service or use a reviewed public-key source. Do not fall back to `dev_env`. |
347
+ | Missing or short attestation secret | Refuses to record the decision. | Supply at least 32 bytes of protected Runner-side key material. |
348
+ | Stored identity proof changed | Apply fails before source mutation. | Investigate ledger integrity. Create a new proposal and approval; do not edit the proof. |
349
+ | Approver lacks an apply role | Apply is refused even after approval. | Use a separately verified operator whose token has one configured `apply_roles` value. |
350
+
351
+ Database availability, database roles, and MCP arguments never substitute for a
352
+ verified operator identity. Keep database least privilege and RLS beneath this
353
+ operator decision boundary.
@@ -1,6 +1,7 @@
1
1
  # Auto Boundary, Scoped Explore, And Protect
2
2
 
3
- Runner 1.6.0 adds a deterministic authoring path for a real application:
3
+ Runner 1.6.4 provides a deterministic, resumable authoring path for a real
4
+ application:
4
5
 
5
6
  ```text
6
7
  Connect staging
@@ -25,7 +26,14 @@ controls underneath Runner. PostgreSQL deployments should use forced row-level
25
26
  security (RLS) where possible; MySQL deployments should use restricted views or
26
27
  tenant-bound credentials.
27
28
 
28
- Export the connection and trusted context in the process that Cursor will use:
29
+ The shortest first run accepts a hidden URL paste or asks before reading
30
+ `DATABASE_URL` from a regular project `.env`:
31
+
32
+ ```bash
33
+ npx -y @synapsor/runner start
34
+ ```
35
+
36
+ For an explicit environment-driven staging run:
29
37
 
30
38
  ```bash
31
39
  export DATABASE_URL='postgresql://runner_reader:REPLACE_ME@127.0.0.1:5432/app'
@@ -108,13 +116,19 @@ candidates start disabled. Auto Boundary never replaces an active contract.
108
116
  No source rows, credentials, tenant values, or principal values are written to
109
117
  these files.
110
118
 
119
+ Workbench previews generated DSL with a local deterministic highlighter. It
120
+ distinguishes DSL keywords from reviewer-defined names, strings, numbers,
121
+ comments, and punctuation while preserving byte-identical plain/copy text.
122
+ Rendering uses escaped DOM text and no external CDN; if highlighting fails, the
123
+ same safe plain source remains visible.
124
+
111
125
  ## Review The Boundary
112
126
 
113
127
  The Workbench requires a human to narrow and confirm:
114
128
 
115
129
  - development or staging deployment profile;
116
130
  - trusted tenant and principal bindings supplied outside model arguments;
117
- - included resources and one-hop relationships;
131
+ - included resources and catalog-proven relationship paths;
118
132
  - selectable fields;
119
133
  - filterable fields and allowed operators;
120
134
  - sortable and groupable fields;
@@ -146,6 +160,52 @@ The immutable digest covers the reviewed resources, field permissions,
146
160
  relationships, scope, role posture, generation lock, compiler/spec version,
147
161
  profile, and every query/privacy budget. Model arguments cannot widen it.
148
162
 
163
+ ## Try Without An External MCP Host
164
+
165
+ Workbench can run the first safe read, bounded aggregate, and Protect flow
166
+ directly. The same authority is available through CLI Try:
167
+
168
+ ```bash
169
+ synapsor-runner try call --list --format json
170
+ synapsor-runner try explore --suggested --json
171
+ synapsor-runner try protect --name analytics.protected_analysis --json
172
+ ```
173
+
174
+ Cursor, Claude, Codex, and generic stdio are optional clients, not onboarding
175
+ dependencies. The packed FitFlow gate proves Workbench, CLI Try, and an
176
+ official-SDK generic stdio client produce the same bounded result and denial
177
+ behavior.
178
+
179
+ ## Optional Workbench Ask Client
180
+
181
+ After the no-model composer succeeds, Workbench can optionally send a
182
+ plain-language question to a developer-selected model provider. This adds a
183
+ client, not authority:
184
+
185
+ ```text
186
+ provider request
187
+ -> exact active Workbench tool registry
188
+ -> official MCP SDK
189
+ -> existing Scoped Explore/runtime validator
190
+ -> reviewed bounded result or refusal
191
+ ```
192
+
193
+ While Explore is active, the provider sees only `app.describe_data` and
194
+ `app.explore_data`. After Protect and Explore shutdown, it sees only activated
195
+ named capabilities. It never receives Protect, activation, approval, apply,
196
+ worker, notification, recovery, credential, or filesystem tools.
197
+
198
+ Provider/model/origin and the exact authority digest require explicit
199
+ direct-egress acknowledgement. Keys come from the local Runner process
200
+ environment or a session-only masked paste; configuration and history remain
201
+ in memory and are cleared on request or shutdown. Ask is restricted to secured
202
+ loopback Workbench in development/staging and is absent from production and
203
+ shared/remote surfaces.
204
+
205
+ The no-model composer, CLI Try, and external MCP routes remain fully supported
206
+ when no provider is configured or a provider is unavailable. See [Workbench
207
+ Ask With Your Model](workbench-ask.md).
208
+
149
209
  ## Add The Authoring Tools To Cursor
150
210
 
151
211
  After activation, let Runner manage only its own project entry:
@@ -202,8 +262,9 @@ analytics database tool. It supports:
202
262
  - bounded top-N results;
203
263
  - at most two reviewed time ranges;
204
264
  - one resource by default;
205
- - at most one inspected, reviewed many-to-one foreign-key path with maximum
206
- fan-out one.
265
+ - up to three activated relationship paths in one plan;
266
+ - one or two inspected, reviewed many-to-one foreign-key links per path, each
267
+ with maximum fan-out one.
207
268
 
208
269
  It does not support arbitrary `DISTINCT`, `HAVING`, formulas, window functions,
209
270
  unions, nested queries, many-to-many joins, system catalogs, user-defined
@@ -211,6 +272,14 @@ functions, or a general join planner. Scope is enforced independently on every
211
272
  participating relation. Runner refuses a plan when cardinality, fan-out,
212
273
  counted entity, or scope cannot be proven.
213
274
 
275
+ Auto Boundary does not activate every discovered path. When a useful question
276
+ needs one inactive but catalog-proven path, Runner refuses the plan and stages
277
+ that exact path for operator review. Workbench shows the foreign-key proof and,
278
+ for optional links, requires an explicit choice between excluding the unmatched
279
+ counted row and keeping it with an empty group value. Activating the new exact
280
+ digest is an operator-plane action; the model cannot perform it. See
281
+ [Reviewed Relationship Paths](reviewed-relationships.md).
282
+
214
283
  Before returning groups, Runner enforces the reviewed minimum cohort size.
215
284
  Small groups are suppressed and revealing totals are withheld. Durable
216
285
  per-session extraction and differencing budgets block repeated slightly
@@ -263,7 +332,7 @@ handles.
263
332
 
264
333
  Choose the useful query in Workbench. Protect freezes:
265
334
 
266
- - resources and reviewed relationship path;
335
+ - resources and reviewed relationship paths;
267
336
  - counted entity, measures, dimensions, and bucket structure;
268
337
  - filters, ordering, top-N, and comparison shape;
269
338
  - tenant/principal as trusted bindings;
@@ -323,16 +392,25 @@ their previous startup, `doctor`, contract, and tool behavior.
323
392
 
324
393
  ## Verify The Reference Journey
325
394
 
326
- The packaged synthetic fixture is under `examples/auto-boundary-churn`.
395
+ The polished packed-artifact journey is under
396
+ `examples/fitflow-guided-onboarding`. The smaller
397
+ `examples/auto-boundary-churn` fixture remains a compatibility and focused
398
+ aggregate-security gate.
327
399
 
328
400
  From a source checkout:
329
401
 
330
402
  ```bash
331
403
  corepack pnpm test:auto-boundary-explore
332
404
  corepack pnpm test:auto-boundary-explore:packed
405
+ corepack pnpm test:guided-onboarding:packed
333
406
  ```
334
407
 
335
- The packed gate proves the PostgreSQL + Next.js + Prisma + Cursor-compatible
336
- MCP + Workbench flow, all aggregate denial/suppression/budget checks, Protect,
337
- production Explore absence, protected-capability survival, durable redacted
338
- audit, and an unchanged source database.
408
+ The packed gates prove the PostgreSQL + Next.js + Prisma + Workbench flow,
409
+ host-neutral CLI/generic-stdio parity, all aggregate
410
+ denial/suppression/budget checks, Protect, production Explore absence,
411
+ protected-capability survival, guided proposal/apply/compensation, verified
412
+ OIDC roles, durable redacted audit, and unchanged source data before every
413
+ authorized mutation.
414
+
415
+ For the timed first-read, Explore, Protect, proposal, and writeback walkthrough,
416
+ use [Database To First Safe Tool](guided-onboarding.md).
@@ -118,6 +118,24 @@ CREATE CAPABILITY billing.propose_late_fee_waiver
118
118
  END
119
119
  ```
120
120
 
121
+ `billing_lead` is a Synapsor contract role, not a database role or secret. For
122
+ shared or production operation, Runner must resolve that exact role from a
123
+ freshly verified operator identity and separately authorize apply. See
124
+ [Approval Roles And Verified Operator
125
+ Identity](approval-roles-and-operator-identity.md).
126
+
127
+ Manual apply remains the default. For an eligible direct single-row
128
+ INSERT/UPDATE, a reviewer may additionally place this clause before `END`:
129
+
130
+ ```sql
131
+ ALLOW SUPERVISED WORKER APPLY
132
+ ```
133
+
134
+ It grants only contract-side permission and becomes part of the exact contract
135
+ digest. Automatic execution still requires an independent deployment allowlist
136
+ for that capability and digest; see [Operator-Supervised Automatic
137
+ Apply](supervised-automatic-apply.md).
138
+
121
139
  Compile and validate:
122
140
 
123
141
  ```bash
@@ -229,6 +247,7 @@ reviewed runner JSON capabilities. Current parity:
229
247
  | proposal weak `conflict_guard` | `CONFLICT GUARD WEAK ROW HASH ACKNOWLEDGED` | 1.4.4 | Explicit legacy escape hatch for an ordinary single-row source-DB UPDATE only. It hashes the captured projection and may miss concurrent changes outside that projection. It is rejected for DELETE, reversible writes, bounded sets, and Runner-ledger authority. |
230
248
  | proposal `approval` | `APPROVAL ROLE billing_lead` | 0.1 | Local mode records the required role; enforcement is still outside the model-facing MCP tool. |
231
249
  | proposal `approval.required_approvals` | `REQUIRE 2 APPROVALS` | 1.1 | Optional 1..10 distinct-reviewer quorum; defaults to 1. |
250
+ | proposal `execution.supervised_worker` | `ALLOW SUPERVISED WORKER APPLY` | 1.6 | Optional contract-side permission for eligible trusted-worker apply. It does nothing without a separate exact-digest deployment allowlist; old auto-approved proposals remain manual-apply. |
232
251
  | proposal `writeback` | `WRITEBACK DIRECT SQL`, `WRITEBACK APP HANDLER EXECUTOR name`, `WRITEBACK CLOUD WORKER`, `WRITEBACK NONE` | 0.1.7 | Handler URLs/tokens stay in `synapsor.runner.json`; contracts carry only the handler name. |
233
252
  | proposal `reversibility` | `REVERSIBLE` | 1.4 | Direct SQL only. Captures a bounded inverse after unambiguous apply; operator `revert` creates a new independently approved proposal. |
234
253
  | evidence options | `REQUIRE EVIDENCE` | 0.1 | Detailed evidence sources/handle prefixes are not expressible in DSL yet; use embedded JSON or generated contract JSON for those. |
@@ -387,8 +406,8 @@ surface.
387
406
  ### Optional Live Freshness
388
407
 
389
408
  The proposal's exact `conflict_guard` already protects its target at apply.
390
- Runner 1.6.1 can additionally recheck that target before local approval and can
391
- bind explicitly reviewed supporting rows to both approval and apply.
409
+ Runner can additionally recheck that target before local approval and bind
410
+ explicitly reviewed supporting rows to both approval and apply.
392
411
 
393
412
  This is deployment wiring, not DSL or canonical contract syntax:
394
413
 
@@ -33,7 +33,7 @@ Run from the Runner repository root after supplying your own environment-bound
33
33
  staging credentials and trusted scope:
34
34
 
35
35
  ```bash
36
- npx -y -p @synapsor/runner synapsor-runner tools preview \
36
+ npx -y @synapsor/runner tools preview \
37
37
  --config ./examples/support-plan-credit/synapsor.runner.json \
38
38
  --store ./tmp/support-plan-credit/local.db
39
39
  ```
@@ -88,17 +88,17 @@ cp .env.example .env
88
88
  # Fill the placeholders in .env, including the one-time Runner token.
89
89
  set -a && . ./.env && set +a
90
90
 
91
- npx -y -p @synapsor/runner synapsor-runner config validate --config ./synapsor.runner.json
92
- npx -y -p @synapsor/runner synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
93
- npx -y -p @synapsor/runner synapsor-runner cloud connect --config ./synapsor.cloud.json
94
- npx -y -p @synapsor/runner synapsor-runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
91
+ npx -y @synapsor/runner config validate --config ./synapsor.runner.json
92
+ npx -y @synapsor/runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
93
+ npx -y @synapsor/runner cloud connect --config ./synapsor.cloud.json
94
+ npx -y @synapsor/runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
95
95
  ```
96
96
 
97
97
  Run the trusted worker in a second operator-controlled terminal:
98
98
 
99
99
  ```bash
100
100
  set -a && . ./.env && set +a
101
- npx -y -p @synapsor/runner synapsor-runner runner start --config ./synapsor.runner.json --store ./.synapsor/local.db
101
+ npx -y @synapsor/runner runner start --config ./synapsor.runner.json --store ./.synapsor/local.db
102
102
  ```
103
103
 
104
104
  For deployment checks or an operator-controlled single claim cycle, use the
@@ -107,13 +107,13 @@ Cloud-approved job and still rechecks the local contract, proposal, tenant,
107
107
  version, bounds, and idempotency guards:
108
108
 
109
109
  ```bash
110
- npx -y -p @synapsor/runner synapsor-runner runner start --once --config ./synapsor.runner.json --store ./.synapsor/local.db
110
+ npx -y @synapsor/runner runner start --once --config ./synapsor.runner.json --store ./.synapsor/local.db
111
111
  ```
112
112
 
113
113
  When a local proposal exists:
114
114
 
115
115
  ```bash
116
- npx -y -p @synapsor/runner synapsor-runner cloud sync latest --config ./synapsor.cloud.json --store ./.synapsor/local.db
116
+ npx -y @synapsor/runner cloud sync latest --config ./synapsor.cloud.json --store ./.synapsor/local.db
117
117
  ```
118
118
 
119
119
  See [Cloud Push](cloud-push.md) and [Runner Bundles](runner-bundles.md).
@@ -64,9 +64,12 @@ bound to a required trusted principal and AND-composed with tenant scope. Run
64
64
  same-tenant denial and shared-ledger evidence-handle isolation.
65
65
  The protected-read parity fixture proves digest- and generation-lock-bound
66
66
  named reads, fixed predicates, reviewed measures/dimensions/time buckets,
67
- one-hop many-to-one limits, suppression, response/query/extraction/
68
- differencing budgets, and rejection of raw SQL or model-controlled trusted
69
- scope. `corepack pnpm test:auto-boundary-explore:packed` proves the complete
67
+ catalog-proven one-hop/star/depth-two many-to-one limits, suppression,
68
+ response/query/extraction/differencing budgets, and rejection of raw SQL or
69
+ model-controlled trusted scope. `corepack pnpm test:reviewed-relationships`
70
+ proves direct and depth-two paths, per-relation scope, nullable semantics,
71
+ demand-driven activation, and fan-out refusal on live PostgreSQL/MySQL.
72
+ `corepack pnpm test:auto-boundary-explore:packed` proves the complete
70
73
  authoring-to-production behavior through packed public artifacts.
71
74
 
72
75
  Additional 0.1 parity coverage currently lives in tests and verification